1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_xmlhelp.hxx"
26 #include "db.hxx"
27 #ifndef _VOS_DIAGNOSE_HXX_
28 #include <vos/diagnose.hxx>
29 #endif
30 #include <osl/thread.h>
31 #include <rtl/uri.hxx>
32 #include <osl/file.hxx>
33 #include <rtl/memory.h>
34 #include <com/sun/star/lang/Locale.hpp>
35 #include <rtl/ustrbuf.hxx>
36 #include "inputstream.hxx"
37 #include <algorithm>
38 #include <string.h>
39
40 // Extensible help
41 #include "com/sun/star/deployment/ExtensionManager.hpp"
42 #include "com/sun/star/deployment/thePackageManagerFactory.hpp"
43 #include <comphelper/processfactory.hxx>
44 #include <com/sun/star/beans/XPropertySet.hpp>
45 #include <com/sun/star/uno/XComponentContext.hpp>
46 #include <com/sun/star/ucb/XCommandEnvironment.hpp>
47 #include <com/sun/star/beans/Optional.hpp>
48 #include <com/sun/star/beans/PropertyValue.hpp>
49 #include <com/sun/star/beans/NamedValue.hpp>
50 #include <com/sun/star/frame/XConfigManager.hpp>
51 #include <com/sun/star/util/XMacroExpander.hpp>
52 #include <com/sun/star/uri/XUriReferenceFactory.hpp>
53 #include <com/sun/star/uri/XVndSunStarExpandUrl.hpp>
54 #include <com/sun/star/script/XInvocation.hpp>
55 #include <comphelper/locale.hxx>
56
57 #include <com/sun/star/awt/XToolkit.hpp>
58 #include <com/sun/star/awt/XExtendedToolkit.hpp>
59 #include <com/sun/star/awt/XWindowPeer.hpp>
60 #include <com/sun/star/awt/XVclWindowPeer.hpp>
61 #include <com/sun/star/awt/XTopWindow.hpp>
62
63 #include <l10ntools/compilehelp.hxx>
64 #include <comphelper/storagehelper.hxx>
65
66 #include "databases.hxx"
67 #include "urlparameter.hxx"
68
69 using namespace chelp;
70 using namespace com::sun::star;
71 using namespace com::sun::star::uno;
72 using namespace com::sun::star::io;
73 using namespace com::sun::star::container;
74 using namespace com::sun::star::i18n;
75 using namespace com::sun::star::lang;
76 using namespace com::sun::star::deployment;
77 using namespace com::sun::star::beans;
78
79
80 static rtl::OUString aSlash( rtl::OUString::createFromAscii( "/" ) );
81 static rtl::OUString aHelpFilesBaseName( rtl::OUString::createFromAscii( "help" ) );
82 static rtl::OUString aHelpMediaType( rtl::OUString::createFromAscii( "application/vnd.sun.star.help" ) );
83
expandURL(const rtl::OUString & aURL)84 rtl::OUString Databases::expandURL( const rtl::OUString& aURL )
85 {
86 osl::MutexGuard aGuard( m_aMutex );
87 rtl::OUString aRetURL = expandURL( aURL, m_xContext );
88 return aRetURL;
89 }
90
expandURL(const rtl::OUString & aURL,Reference<uno::XComponentContext> xContext)91 rtl::OUString Databases::expandURL( const rtl::OUString& aURL, Reference< uno::XComponentContext > xContext )
92 {
93 static Reference< util::XMacroExpander > xMacroExpander;
94 static Reference< uri::XUriReferenceFactory > xFac;
95
96 if( !xContext.is() )
97 return rtl::OUString();
98
99 if( !xMacroExpander.is() || !xFac.is() )
100 {
101 Reference< XMultiComponentFactory > xSMgr( xContext->getServiceManager(), UNO_QUERY );
102
103 xFac = Reference< uri::XUriReferenceFactory >(
104 xSMgr->createInstanceWithContext( rtl::OUString::createFromAscii(
105 "com.sun.star.uri.UriReferenceFactory"), xContext ) , UNO_QUERY );
106 if( !xFac.is() )
107 {
108 throw RuntimeException(
109 ::rtl::OUString::createFromAscii( "Databases::expand(), could not instatiate UriReferenceFactory." ),
110 Reference< XInterface >() );
111 }
112
113 xMacroExpander = Reference< util::XMacroExpander >(
114 xContext->getValueByName(
115 ::rtl::OUString::createFromAscii( "/singletons/com.sun.star.util.theMacroExpander" ) ),
116 UNO_QUERY_THROW );
117 }
118
119 rtl::OUString aRetURL = aURL;
120 if( xMacroExpander.is() )
121 {
122 Reference< uri::XUriReference > uriRef;
123 for (;;)
124 {
125 uriRef = Reference< uri::XUriReference >( xFac->parse( aRetURL ), UNO_QUERY );
126 if ( uriRef.is() )
127 {
128 Reference < uri::XVndSunStarExpandUrl > sxUri( uriRef, UNO_QUERY );
129 if( !sxUri.is() )
130 break;
131
132 aRetURL = sxUri->expand( xMacroExpander );
133 }
134 }
135 }
136 return aRetURL;
137 }
138
Databases(sal_Bool showBasic,const rtl::OUString & instPath,const com::sun::star::uno::Sequence<rtl::OUString> & imagesZipPaths,const rtl::OUString & productName,const rtl::OUString & productVersion,const rtl::OUString & styleSheet,Reference<uno::XComponentContext> xContext)139 Databases::Databases( sal_Bool showBasic,
140 const rtl::OUString& instPath,
141 const com::sun::star::uno::Sequence< rtl::OUString >& imagesZipPaths,
142 const rtl::OUString& productName,
143 const rtl::OUString& productVersion,
144 const rtl::OUString& styleSheet,
145 Reference< uno::XComponentContext > xContext )
146 : m_xContext( xContext ),
147 m_bShowBasic(showBasic),
148 m_nErrorDocLength( 0 ),
149 m_pErrorDoc( 0 ),
150 m_nCustomCSSDocLength( 0 ),
151 m_pCustomCSSDoc( 0 ),
152 m_aCSS(styleSheet.toAsciiLowerCase()),
153 newProdName(rtl::OUString::createFromAscii( "$[officename]" ) ),
154 newProdVersion(rtl::OUString::createFromAscii( "$[officeversion]" ) ),
155 prodName( rtl::OUString::createFromAscii( "%PRODUCTNAME" ) ),
156 prodVersion( rtl::OUString::createFromAscii( "%PRODUCTVERSION" ) ),
157 vendName( rtl::OUString::createFromAscii( "%VENDORNAME" ) ),
158 vendVersion( rtl::OUString::createFromAscii( "%VENDORVERSION" ) ),
159 vendShort( rtl::OUString::createFromAscii( "%VENDORSHORT" ) ),
160 m_aImagesZipPaths( imagesZipPaths ),
161 m_nSymbolsStyle( 0 )
162 {
163 m_xSMgr = Reference< XMultiComponentFactory >( m_xContext->getServiceManager(), UNO_QUERY );
164
165 m_vAdd[0] = 12;
166 m_vAdd[1] = 15;
167 m_vAdd[2] = 11;
168 m_vAdd[3] = 14;
169 m_vAdd[4] = 12;
170 m_vAdd[5] = 13;
171 m_vAdd[6] = 16;
172
173 m_vReplacement[0] = productName;
174 m_vReplacement[1] = productVersion;
175 // m_vReplacement[2...4] (vendorName/-Version/-Short) are empty strings
176 m_vReplacement[5] = productName;
177 m_vReplacement[6] = productVersion;
178
179 setInstallPath( instPath );
180
181 m_xSFA = Reference< ucb::XSimpleFileAccess >(
182 m_xSMgr->createInstanceWithContext( rtl::OUString::createFromAscii( "com.sun.star.ucb.SimpleFileAccess" ),
183 m_xContext ), UNO_QUERY_THROW );
184 }
185
~Databases()186 Databases::~Databases()
187 {
188 // release stylesheet
189
190 delete[] m_pCustomCSSDoc;
191
192 // release errorDocument
193
194 delete[] m_pErrorDoc;
195
196 // unload the databases
197
198 {
199 // DatabasesTable
200 DatabasesTable::iterator it = m_aDatabases.begin();
201 while( it != m_aDatabases.end() )
202 {
203 delete it->second;
204 ++it;
205 }
206 }
207
208 {
209 // ModInfoTable
210
211 ModInfoTable::iterator it = m_aModInfo.begin();
212 while( it != m_aModInfo.end() )
213 {
214 delete it->second;
215 ++it;
216 }
217 }
218
219 {
220 // KeywordInfoTable
221
222 KeywordInfoTable::iterator it = m_aKeywordInfo.begin();
223 while( it != m_aKeywordInfo.end() )
224 {
225 delete it->second;
226 ++it;
227 }
228 }
229 }
230
impl_getZipFile(Sequence<rtl::OUString> & rImagesZipPaths,const rtl::OUString & rZipName,rtl::OUString & rFileName)231 static bool impl_getZipFile(
232 Sequence< rtl::OUString > & rImagesZipPaths,
233 const rtl::OUString & rZipName,
234 rtl::OUString & rFileName )
235 {
236 const rtl::OUString *pPathArray = rImagesZipPaths.getArray();
237 for ( int i = 0; i < rImagesZipPaths.getLength(); ++i )
238 {
239 rFileName = pPathArray[ i ];
240 if ( rFileName.getLength() )
241 {
242 if ( 1 + rFileName.lastIndexOf( '/' ) != rFileName.getLength() )
243 {
244 rFileName += rtl::OUString::createFromAscii( "/" );
245 }
246 rFileName += rZipName;
247
248 // test existence
249 osl::DirectoryItem aDirItem;
250 if ( osl::DirectoryItem::get( rFileName, aDirItem ) == osl::FileBase::E_None )
251 return true;
252 }
253 }
254 return false;
255 }
256
getImagesZipFileURL()257 rtl::OString Databases::getImagesZipFileURL()
258 {
259 //sal_Int16 nSymbolsStyle = SvtMiscOptions().GetCurrentSymbolsStyle();
260 sal_Int16 nSymbolsStyle = 0;
261 try
262 {
263 uno::Reference< lang::XMultiServiceFactory > xConfigProvider(
264 m_xSMgr ->createInstanceWithContext(::rtl::OUString::createFromAscii("com.sun.star.configuration.ConfigurationProvider"), m_xContext), uno::UNO_QUERY_THROW);
265
266 // set root path
267 uno::Sequence < uno::Any > lParams(1);
268 beans::PropertyValue aParam ;
269 aParam.Name = ::rtl::OUString::createFromAscii("nodepath");
270 aParam.Value <<= ::rtl::OUString::createFromAscii("org.openoffice.Office.Common");
271 lParams[0] = uno::makeAny(aParam);
272
273 // open it
274 uno::Reference< uno::XInterface > xCFG( xConfigProvider->createInstanceWithArguments(
275 ::rtl::OUString::createFromAscii("com.sun.star.configuration.ConfigurationAccess"),
276 lParams) );
277
278 bool bChanged = false;
279 uno::Reference< container::XHierarchicalNameAccess > xAccess(xCFG, uno::UNO_QUERY_THROW);
280 uno::Any aResult = xAccess->getByHierarchicalName(::rtl::OUString::createFromAscii("Misc/SymbolSet"));
281 if ( (aResult >>= nSymbolsStyle) && m_nSymbolsStyle != nSymbolsStyle )
282 {
283 m_nSymbolsStyle = nSymbolsStyle;
284 bChanged = true;
285 }
286
287 if ( !m_aImagesZipFileURL.getLength() || bChanged )
288 {
289 rtl::OUString aImageZip, aSymbolsStyleName;
290 aResult = xAccess->getByHierarchicalName(::rtl::OUString::createFromAscii("Misc/SymbolStyle"));
291 aResult >>= aSymbolsStyleName;
292
293 bool bFound = false;
294 if ( aSymbolsStyleName.getLength() != 0 )
295 {
296 rtl::OUString aZipName = rtl::OUString::createFromAscii( "images_" );
297 aZipName += aSymbolsStyleName;
298 aZipName += rtl::OUString::createFromAscii( ".zip" );
299
300 bFound = impl_getZipFile( m_aImagesZipPaths, aZipName, aImageZip );
301 }
302
303 if ( ! bFound )
304 bFound = impl_getZipFile( m_aImagesZipPaths, rtl::OUString::createFromAscii( "images.zip" ), aImageZip );
305
306 if ( ! bFound )
307 aImageZip = rtl::OUString();
308
309 m_aImagesZipFileURL = rtl::OUStringToOString(
310 rtl::Uri::encode(
311 aImageZip,
312 rtl_UriCharClassPchar,
313 rtl_UriEncodeIgnoreEscapes,
314 RTL_TEXTENCODING_UTF8 ), RTL_TEXTENCODING_UTF8 );
315 }
316 }
317 catch ( NoSuchElementException const & )
318 {
319 }
320
321 return m_aImagesZipFileURL;
322 }
323
replaceName(rtl::OUString & oustring) const324 void Databases::replaceName( rtl::OUString& oustring ) const
325 {
326 sal_Int32 idx = -1,idx1 = -1,idx2 = -1,k = 0,off;
327 bool cap = false;
328 rtl::OUStringBuffer aStrBuf( 0 );
329
330 while( true )
331 {
332 ++idx;
333 idx1 = oustring.indexOf( sal_Unicode('%'),idx);
334 idx2 = oustring.indexOf( sal_Unicode('$'),idx);
335
336 if(idx1 == -1 && idx2 == -1)
337 break;
338
339 if(idx1 == -1)
340 idx = idx2;
341 else if(idx2 == -1)
342 idx = idx1;
343 else {
344 // no index is zero
345 if(idx1 < idx2)
346 idx = idx1;
347 else if(idx2 < idx1 )
348 idx = idx2;
349 }
350
351 if( oustring.indexOf( prodName,idx ) == idx )
352 off = PRODUCTNAME;
353 else if( oustring.indexOf( prodVersion,idx ) == idx )
354 off = PRODUCTVERSION;
355 else if( oustring.indexOf( vendName,idx ) == idx )
356 off = VENDORNAME;
357 else if( oustring.indexOf( vendVersion,idx ) == idx )
358 off = VENDORVERSION;
359 else if( oustring.indexOf( vendShort,idx ) == idx )
360 off = VENDORSHORT;
361 else if( oustring.indexOf( newProdName,idx ) == idx )
362 off = NEWPRODUCTNAME;
363 else if( oustring.indexOf( newProdVersion,idx ) == idx )
364 off = NEWPRODUCTVERSION;
365 else
366 off = -1;
367
368 if( off != -1 )
369 {
370 if( ! cap )
371 {
372 cap = true;
373 aStrBuf.ensureCapacity( 256 );
374 }
375
376 aStrBuf.append( &oustring.getStr()[k],idx - k );
377 aStrBuf.append( m_vReplacement[off] );
378 k = idx + m_vAdd[off];
379 }
380 }
381
382 if( cap )
383 {
384 if( k < oustring.getLength() )
385 aStrBuf.append( &oustring.getStr()[k],oustring.getLength()-k );
386 oustring = aStrBuf.makeStringAndClear();
387 }
388 }
389
390
391
392
getInstallPathAsSystemPath()393 rtl::OUString Databases::getInstallPathAsSystemPath()
394 {
395 osl::MutexGuard aGuard( m_aMutex );
396
397 if( ! m_aInstallDirectoryAsSystemPath.getLength() )
398 {
399 #ifdef DBG_UTIL
400 bool bla =
401 osl::FileBase::E_None ==
402 osl::FileBase::getSystemPathFromFileURL( m_aInstallDirectory,m_aInstallDirectoryAsSystemPath );
403 VOS_ENSURE( bla,"HelpProvider, no installpath" );
404 #else
405 osl::FileBase::getSystemPathFromFileURL( m_aInstallDirectory,m_aInstallDirectoryAsSystemPath );
406 #endif
407 }
408
409 return m_aInstallDirectoryAsSystemPath;
410 }
411
getInstallPathAsURL()412 rtl::OUString Databases::getInstallPathAsURL()
413 {
414 osl::MutexGuard aGuard( m_aMutex );
415
416 return m_aInstallDirectory;
417 }
418
419
getModuleList(const rtl::OUString & Language)420 const std::vector< rtl::OUString >& Databases::getModuleList( const rtl::OUString& Language )
421 {
422 if( m_avModules.size() == 0 )
423 {
424 rtl::OUString fileName,dirName = getInstallPathAsURL() + processLang( Language );
425 osl::Directory dirFile( dirName );
426
427 osl::DirectoryItem aDirItem;
428 osl::FileStatus aStatus( FileStatusMask_FileName );
429
430 sal_Int32 idx;
431
432 if( osl::FileBase::E_None != dirFile.open() )
433 return m_avModules;
434
435 while( dirFile.getNextItem( aDirItem ) == osl::FileBase::E_None &&
436 aDirItem.getFileStatus( aStatus ) == osl::FileBase::E_None )
437 {
438 if( ! aStatus.isValid( FileStatusMask_FileName ) )
439 continue;
440
441 fileName = aStatus.getFileName();
442
443 // Check, whether fileName is of the form *.cfg
444 idx = fileName.lastIndexOf( sal_Unicode( '.' ) );
445
446 if( idx == -1 )
447 continue;
448
449 const sal_Unicode* str = fileName.getStr();
450
451 if( fileName.getLength() == idx + 4 &&
452 ( str[idx + 1] == 'c' || str[idx + 1] == 'C' ) &&
453 ( str[idx + 2] == 'f' || str[idx + 2] == 'F' ) &&
454 ( str[idx + 3] == 'g' || str[idx + 3] == 'G' ) &&
455 ( fileName = fileName.copy(0,idx).toAsciiLowerCase() ).compareToAscii( "picture" ) != 0 ) {
456 if(! m_bShowBasic && fileName.compareToAscii("sbasic") == 0 )
457 continue;
458 m_avModules.push_back( fileName );
459 }
460 }
461 }
462 return m_avModules;
463 }
464
465
466
getStaticInformationForModule(const rtl::OUString & Module,const rtl::OUString & Language)467 StaticModuleInformation* Databases::getStaticInformationForModule( const rtl::OUString& Module,
468 const rtl::OUString& Language )
469 {
470 osl::MutexGuard aGuard( m_aMutex );
471
472 rtl::OUString key = processLang(Language) + rtl::OUString::createFromAscii( "/" ) + Module;
473
474 std::pair< ModInfoTable::iterator,bool > aPair =
475 m_aModInfo.insert( ModInfoTable::value_type( key,0 ) );
476
477 ModInfoTable::iterator it = aPair.first;
478
479 if( aPair.second && ! it->second )
480 {
481 osl::File cfgFile( getInstallPathAsURL() +
482 key +
483 rtl::OUString::createFromAscii( ".cfg" ) );
484
485 if( osl::FileBase::E_None != cfgFile.open( OpenFlag_Read ) )
486 it->second = 0;
487 else
488 {
489 sal_uInt32 pos = 0;
490 sal_uInt64 nRead;
491 sal_Char buffer[2048];
492 sal_Unicode lineBuffer[1028];
493 rtl::OUString fileContent;
494
495 while( osl::FileBase::E_None == cfgFile.read( &buffer,2048,nRead ) && nRead )
496 fileContent += rtl::OUString( buffer,sal_Int32( nRead ),RTL_TEXTENCODING_UTF8 );
497
498 cfgFile.close();
499
500 const sal_Unicode* str = fileContent.getStr();
501 rtl::OUString current,lang_,program,startid,title,heading,fulltext;
502 rtl::OUString order = rtl::OUString::createFromAscii( "1" );
503
504 for( sal_Int32 i = 0;i < fileContent.getLength();i++ )
505 {
506 sal_Unicode ch = str[ i ];
507 if( ch == sal_Unicode( '\n' ) || ch == sal_Unicode( '\r' ) )
508 {
509 if( pos )
510 {
511 current = rtl::OUString( lineBuffer,pos );
512
513 if( current.compareToAscii( "Title",5 ) == 0 )
514 {
515 title = current.copy( current.indexOf(sal_Unicode( '=' ) ) + 1 );
516 }
517 else if( current.compareToAscii( "Start",5 ) == 0 )
518 {
519 startid = current.copy( current.indexOf('=') + 1 );
520 }
521 else if( current.compareToAscii( "Language",8 ) == 0 )
522 {
523 lang_ = current.copy( current.indexOf('=') + 1 );
524 }
525 else if( current.compareToAscii( "Program",7 ) == 0 )
526 {
527 program = current.copy( current.indexOf('=') + 1 );
528 }
529 else if( current.compareToAscii( "Heading",7 ) == 0 )
530 {
531 heading = current.copy( current.indexOf('=') + 1 );
532 }
533 else if( current.compareToAscii( "FullText",8 ) == 0 )
534 {
535 fulltext = current.copy( current.indexOf('=') + 1 );
536 }
537 else if( current.compareToAscii( "Order",5 ) == 0 )
538 {
539 order = current.copy( current.indexOf('=') + 1 );
540 }
541 }
542 pos = 0;
543 }
544 else
545 lineBuffer[ pos++ ] = ch;
546 }
547 replaceName( title );
548 it->second = new StaticModuleInformation( title,
549 startid,
550 program,
551 heading,
552 fulltext,
553 order );
554 }
555 }
556
557 return it->second;
558 }
559
560
561
562
processLang(const rtl::OUString & Language)563 rtl::OUString Databases::processLang( const rtl::OUString& Language )
564 {
565 osl::MutexGuard aGuard( m_aMutex );
566
567 rtl::OUString ret;
568 LangSetTable::iterator it = m_aLangSet.find( Language );
569
570 if( it == m_aLangSet.end() )
571 {
572 sal_Int32 idx;
573 osl::DirectoryItem aDirItem;
574
575 if( osl::FileBase::E_None == osl::DirectoryItem::get( getInstallPathAsURL() + Language,aDirItem ) )
576 {
577 ret = Language;
578 m_aLangSet[ Language ] = ret;
579 }
580 else if( ( ( idx = Language.indexOf( '-' ) ) != -1 ||
581 ( idx = Language.indexOf( '_' ) ) != -1 ) &&
582 osl::FileBase::E_None == osl::DirectoryItem::get( getInstallPathAsURL() + Language.copy( 0,idx ),
583 aDirItem ) )
584 {
585 ret = Language.copy( 0,idx );
586 m_aLangSet[ Language ] = ret;
587 }
588 }
589 else
590 ret = it->second;
591
592 return ret;
593 }
594
595
country(const rtl::OUString & Language)596 rtl::OUString Databases::country( const rtl::OUString& Language )
597 {
598 sal_Int32 idx;
599 if( ( idx = Language.indexOf( '-' ) ) != -1 ||
600 ( idx = Language.indexOf( '_' ) ) != -1 )
601 return Language.copy( 1+idx );
602
603 return rtl::OUString();
604 }
605
606
607
getHelpDataFile(const rtl::OUString & Database,const rtl::OUString & Language,bool helpText,const rtl::OUString * pExtensionPath)608 helpdatafileproxy::Hdf* Databases::getHelpDataFile( const rtl::OUString& Database,
609 const rtl::OUString& Language, bool helpText,
610 const rtl::OUString* pExtensionPath )
611 {
612 if( ! Database.getLength() || ! Language.getLength() )
613 return 0;
614
615 osl::MutexGuard aGuard( m_aMutex );
616
617
618 rtl::OUString aFileExt( rtl::OUString::createFromAscii( helpText ? ".ht" : ".db" ) );
619 rtl::OUString dbFileName = aSlash + Database + aFileExt;
620 rtl::OUString key;
621 if( pExtensionPath == NULL )
622 key = processLang( Language ) + dbFileName;
623 else
624 key = *pExtensionPath + Language + dbFileName; // make unique, don't change language
625
626 std::pair< DatabasesTable::iterator,bool > aPair =
627 m_aDatabases.insert( DatabasesTable::value_type( key,0 ) );
628
629 DatabasesTable::iterator it = aPair.first;
630
631 if( aPair.second && ! it->second )
632 {
633 helpdatafileproxy::Hdf* pHdf = 0;
634
635 rtl::OUString fileURL;
636 if( pExtensionPath )
637 fileURL = expandURL(*pExtensionPath) + Language + dbFileName;
638 else
639 fileURL = getInstallPathAsURL() + key;
640
641 rtl::OUString fileNameHDFHelp( fileURL );
642 //Extensions always use the new format
643 if( pExtensionPath != NULL )
644 fileNameHDFHelp += rtl::OUString::createFromAscii( "_" );
645 //SimpleFileAccess takes file URLs as arguments!!! Using filenames works accidentally but
646 //fails for example when using long path names on Windows (starting with \\?\)
647 if( m_xSFA->exists( fileNameHDFHelp ) )
648 {
649 pHdf = new helpdatafileproxy::Hdf( fileNameHDFHelp, m_xSFA );
650 }
651
652 it->second = pHdf;
653 }
654
655 return it->second;
656 }
657
658 Reference< XCollator >
getCollator(const rtl::OUString & Language,const rtl::OUString & System)659 Databases::getCollator( const rtl::OUString& Language,
660 const rtl::OUString& System )
661 {
662 (void)System;
663
664 rtl::OUString key = Language;
665
666 osl::MutexGuard aGuard( m_aMutex );
667
668 CollatorTable::iterator it =
669 m_aCollatorTable.insert( CollatorTable::value_type( key,0 ) ).first;
670
671 if( ! it->second.is() )
672 {
673 it->second =
674 Reference< XCollator > (
675 m_xSMgr->createInstanceWithContext( rtl::OUString::createFromAscii( "com.sun.star.i18n.Collator" ),
676 m_xContext ), UNO_QUERY );
677 rtl::OUString langStr = processLang(Language);
678 rtl::OUString countryStr = country(Language);
679 if( !countryStr.getLength() )
680 {
681 if( langStr.compareToAscii("de") == 0 )
682 countryStr = rtl::OUString::createFromAscii("DE");
683 else if( langStr.compareToAscii("en") == 0 )
684 countryStr = rtl::OUString::createFromAscii("US");
685 else if( langStr.compareToAscii("es") == 0 )
686 countryStr = rtl::OUString::createFromAscii("ES");
687 else if( langStr.compareToAscii("it") == 0 )
688 countryStr = rtl::OUString::createFromAscii("IT");
689 else if( langStr.compareToAscii("fr") == 0 )
690 countryStr = rtl::OUString::createFromAscii("FR");
691 else if( langStr.compareToAscii("sv") == 0 )
692 countryStr = rtl::OUString::createFromAscii("SE");
693 else if( langStr.compareToAscii("ja") == 0 )
694 countryStr = rtl::OUString::createFromAscii("JP");
695 else if( langStr.compareToAscii("ko") == 0 )
696 countryStr = rtl::OUString::createFromAscii("KR");
697 }
698 it->second->loadDefaultCollator( Locale( langStr,
699 countryStr,
700 rtl::OUString() ),
701 0 );
702 }
703
704 return it->second;
705 }
706
707
708
709 namespace chelp {
710
711 struct KeywordElementComparator
712 {
KeywordElementComparatorchelp::KeywordElementComparator713 KeywordElementComparator( const Reference< XCollator >& xCollator )
714 : m_xCollator( xCollator )
715 { }
716
operator ()chelp::KeywordElementComparator717 bool operator()( const KeywordInfo::KeywordElement& la,
718 const KeywordInfo::KeywordElement& ra ) const
719 {
720 const rtl::OUString& l = la.key;
721 const rtl::OUString& r = ra.key;
722
723 bool ret;
724
725 if( m_xCollator.is() )
726 {
727 sal_Int32 l1 = l.indexOf( sal_Unicode( ';' ) );
728 sal_Int32 l3 = ( l1 == -1 ? l.getLength() : l1 );
729
730 sal_Int32 r1 = r.indexOf( sal_Unicode( ';' ) );
731 sal_Int32 r3 = ( r1 == -1 ? r.getLength() : r1 );
732
733 sal_Int32 c1 = m_xCollator->compareSubstring( l,0,l3,r,0,r3 );
734
735 if( c1 == +1 )
736 ret = false;
737 else if( c1 == 0 )
738 {
739 sal_Int32 l2 = l.getLength() - l1 - 1;
740 sal_Int32 r2 = r.getLength() - r1 - 1;
741 ret = ( m_xCollator->compareSubstring( l,1+l1,l2,r,1+r1,r2 ) < 0 );
742 }
743 else
744 ret = true;
745 }
746 else
747 ret = bool( l < r );
748
749 return ret;
750 }
751
752 Reference< XCollator > m_xCollator;
753 }; // end struct KeywordElementComparator
754
755 }
756
757
758
KeywordElement(Databases * pDatabases,helpdatafileproxy::Hdf * pHdf,rtl::OUString & ky,rtl::OUString & data)759 KeywordInfo::KeywordElement::KeywordElement( Databases *pDatabases,
760 helpdatafileproxy::Hdf* pHdf,
761 rtl::OUString& ky,
762 rtl::OUString& data )
763 : key( ky )
764 {
765 pDatabases->replaceName( key );
766 init( pDatabases,pHdf,data );
767 }
768
769
770
init(Databases * pDatabases,helpdatafileproxy::Hdf * pHdf,const rtl::OUString & ids)771 void KeywordInfo::KeywordElement::init( Databases *pDatabases,helpdatafileproxy::Hdf* pHdf,const rtl::OUString& ids )
772 {
773 const sal_Unicode* idstr = ids.getStr();
774 std::vector< rtl::OUString > id,anchor;
775 int idx = -1,k;
776 while( ( idx = ids.indexOf( ';',k = ++idx ) ) != -1 )
777 {
778 int h = ids.indexOf( sal_Unicode( '#' ),k );
779 if( h < idx )
780 {
781 // found an anchor
782 id.push_back( rtl::OUString( &idstr[k],h-k ) );
783 anchor.push_back( rtl::OUString( &idstr[h+1],idx-h-1 ) );
784 }
785 else
786 {
787 id.push_back( rtl::OUString( &idstr[k],idx-k ) );
788 anchor.push_back( rtl::OUString() );
789 }
790 }
791
792 listId.realloc( id.size() );
793 listAnchor.realloc( id.size() );
794 listTitle.realloc( id.size() );
795
796 int nSize = 0;
797 const sal_Char* pData = NULL;
798 const sal_Char pEmpty[] = "";
799
800 for( sal_uInt32 i = 0; i < id.size(); ++i )
801 {
802 listId[i] = id[i];
803 listAnchor[i] = anchor[i];
804
805 nSize = 0;
806 pData = pEmpty;
807 if( pHdf )
808 {
809 rtl::OString idi( id[i].getStr(),id[i].getLength(),RTL_TEXTENCODING_UTF8 );
810 helpdatafileproxy::HDFData aHDFData;
811 bool bSuccess = pHdf->getValueForKey( idi, aHDFData );
812 if( bSuccess )
813 {
814 nSize = aHDFData.getSize();
815 pData = aHDFData.getData();
816 }
817 }
818
819 DbtToStringConverter converter( pData, nSize );
820
821 rtl::OUString title = converter.getTitle();
822 pDatabases->replaceName( title );
823 listTitle[i] = title;
824 }
825 }
826
827
828
KeywordInfo(const std::vector<KeywordElement> & aVec)829 KeywordInfo::KeywordInfo( const std::vector< KeywordElement >& aVec )
830 : listKey( aVec.size() ),
831 listId( aVec.size() ),
832 listAnchor( aVec.size() ),
833 listTitle( aVec.size() )
834 {
835 for( unsigned int i = 0; i < aVec.size(); ++i )
836 {
837 listKey[i] = aVec[i].key;
838 listId[i] = aVec[i].listId;
839 listAnchor[i] = aVec[i].listAnchor;
840 listTitle[i] = aVec[i].listTitle;
841 }
842 }
843
checkModuleMatchForExtension(const rtl::OUString & Database,const rtl::OUString & doclist)844 bool Databases::checkModuleMatchForExtension
845 ( const rtl::OUString& Database, const rtl::OUString& doclist )
846 {
847 bool bBelongsToDatabase = true;
848
849 // Analyse doclist string to find module assignments
850 bool bFoundAtLeastOneModule = false;
851 bool bModuleMatch = false;
852 sal_Int32 nLen = doclist.getLength();
853 sal_Int32 nLastFound = doclist.lastIndexOf( sal_Unicode(';') );
854 if( nLastFound == -1 )
855 nLastFound = nLen;
856 const sal_Unicode* pStr = doclist.getStr();
857 sal_Int32 nFound = doclist.lastIndexOf( sal_Unicode('_') );
858 while( nFound != -1 )
859 {
860 // Simple optimization, stop if '_' is followed by "id"
861 if( nLen - nFound > 2 )
862 {
863 if( pStr[ nFound + 1 ] == sal_Unicode('i') &&
864 pStr[ nFound + 2 ] == sal_Unicode('d') )
865 break;
866 }
867
868 rtl::OUString aModule = doclist.copy( nFound + 1, nLastFound - nFound - 1 );
869 std::vector< rtl::OUString >::iterator result = std::find( m_avModules.begin(), m_avModules.end(), aModule );
870 if( result != m_avModules.end() )
871 {
872 bFoundAtLeastOneModule = true;
873 if( Database == aModule )
874 {
875 bModuleMatch = true;
876 break;
877 }
878 }
879
880 nLastFound = nFound;
881 if( nLastFound == 0 )
882 break;
883 nFound = doclist.lastIndexOf( sal_Unicode('_'), nLastFound - 1 );
884 }
885
886 if( bFoundAtLeastOneModule && !bModuleMatch )
887 bBelongsToDatabase = false;
888
889 return bBelongsToDatabase;
890 }
891
892
getKeyword(const rtl::OUString & Database,const rtl::OUString & Language)893 KeywordInfo* Databases::getKeyword( const rtl::OUString& Database,
894 const rtl::OUString& Language )
895 {
896 osl::MutexGuard aGuard( m_aMutex );
897
898 rtl::OUString key = processLang(Language) + rtl::OUString::createFromAscii( "/" ) + Database;
899
900 std::pair< KeywordInfoTable::iterator,bool > aPair =
901 m_aKeywordInfo.insert( KeywordInfoTable::value_type( key,0 ) );
902
903 KeywordInfoTable::iterator it = aPair.first;
904
905 if( aPair.second && ! it->second )
906 {
907 std::vector<KeywordInfo::KeywordElement> aVector;
908
909 KeyDataBaseFileIterator aDbFileIt( m_xContext, *this, Database, Language );
910 rtl::OUString fileURL;
911 bool bExtension = false;
912 while( (fileURL = aDbFileIt.nextDbFile( bExtension )).getLength() > 0 )
913 {
914 rtl::OUString fileNameHDFHelp( fileURL );
915 if( bExtension )
916 fileNameHDFHelp += rtl::OUString::createFromAscii( "_" );
917 if( m_xSFA->exists( fileNameHDFHelp ) )
918 {
919 helpdatafileproxy::Hdf aHdf( fileNameHDFHelp, m_xSFA );
920
921 helpdatafileproxy::HDFData aKey;
922 helpdatafileproxy::HDFData aValue;
923 if( aHdf.startIteration() )
924 {
925 helpdatafileproxy::Hdf* pHdf = getHelpDataFile( Database,Language );
926 if( pHdf != NULL )
927 {
928 bool bOptimizeForPerformance = true;
929 pHdf->releaseHashMap();
930 pHdf->createHashMap( bOptimizeForPerformance );
931 }
932
933 while( aHdf.getNextKeyAndValue( aKey, aValue ) )
934 {
935 rtl::OUString keyword( aKey.getData(), aKey.getSize(),
936 RTL_TEXTENCODING_UTF8 );
937 rtl::OUString doclist( aValue.getData(), aValue.getSize(),
938 RTL_TEXTENCODING_UTF8 );
939
940 bool bBelongsToDatabase = true;
941 if( bExtension )
942 bBelongsToDatabase = checkModuleMatchForExtension( Database, doclist );
943
944 if( !bBelongsToDatabase )
945 continue;
946
947 aVector.push_back( KeywordInfo::KeywordElement( this,
948 pHdf,
949 keyword,
950 doclist ) );
951 }
952 aHdf.stopIteration();
953
954 if( pHdf != NULL )
955 pHdf->releaseHashMap();
956 }
957 }
958 }
959
960 // sorting
961 Reference< XCollator > xCollator = getCollator( Language,rtl::OUString());
962 KeywordElementComparator aComparator( xCollator );
963 std::sort(aVector.begin(),aVector.end(),aComparator);
964
965 KeywordInfo* pInfo = it->second = new KeywordInfo( aVector );
966 (void)pInfo;
967 }
968
969 return it->second;
970 }
971
jarFile(const rtl::OUString & jar,const rtl::OUString & Language)972 Reference< XHierarchicalNameAccess > Databases::jarFile( const rtl::OUString& jar,
973 const rtl::OUString& Language )
974 {
975 if( ! jar.getLength() ||
976 ! Language.getLength() )
977 {
978 return Reference< XHierarchicalNameAccess >( 0 );
979 }
980 rtl::OUString key = processLang(Language) + aSlash + jar;
981
982 osl::MutexGuard aGuard( m_aMutex );
983
984 ZipFileTable::iterator it =
985 m_aZipFileTable.insert( ZipFileTable::value_type( key,Reference< XHierarchicalNameAccess >(0) ) ).first;
986
987 if( ! it->second.is() )
988 {
989 rtl::OUString zipFile;
990 try
991 {
992 // Extension jar file? Search for ?
993 sal_Int32 nQuestionMark1 = jar.indexOf( sal_Unicode('?') );
994 sal_Int32 nQuestionMark2 = jar.lastIndexOf( sal_Unicode('?') );
995 if( nQuestionMark1 != -1 && nQuestionMark2 != -1 && nQuestionMark1 != nQuestionMark2 )
996 {
997 ::rtl::OUString aExtensionPath = jar.copy( nQuestionMark1 + 1, nQuestionMark2 - nQuestionMark1 - 1 );
998 ::rtl::OUString aPureJar = jar.copy( nQuestionMark2 + 1 );
999
1000 rtl::OUStringBuffer aStrBuf;
1001 aStrBuf.append( aExtensionPath );
1002 aStrBuf.append( aSlash );
1003 aStrBuf.append( aPureJar );
1004
1005 zipFile = expandURL( aStrBuf.makeStringAndClear() );
1006 }
1007 else
1008 {
1009 zipFile = getInstallPathAsURL() + key;
1010 }
1011
1012 Sequence< Any > aArguments( 2 );
1013
1014 XInputStream_impl* p = new XInputStream_impl( zipFile );
1015 if( p->CtorSuccess() )
1016 {
1017 Reference< XInputStream > xInputStream( p );
1018 aArguments[ 0 ] <<= xInputStream;
1019 }
1020 else
1021 {
1022 delete p;
1023 aArguments[ 0 ] <<= zipFile;
1024 }
1025
1026 // let ZipPackage be used ( no manifest.xml is required )
1027 beans::NamedValue aArg;
1028 aArg.Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "StorageFormat" ) );
1029 aArg.Value <<= ZIP_STORAGE_FORMAT_STRING;
1030 aArguments[ 1 ] <<= aArg;
1031
1032 Reference< XInterface > xIfc
1033 = m_xSMgr->createInstanceWithArgumentsAndContext(
1034 rtl::OUString::createFromAscii(
1035 "com.sun.star.packages.comp.ZipPackage" ),
1036 aArguments, m_xContext );
1037
1038 if ( xIfc.is() )
1039 {
1040 it->second = Reference< XHierarchicalNameAccess >( xIfc, UNO_QUERY );
1041
1042 VOS_ENSURE( it->second.is(),
1043 "ContentProvider::createPackage - "
1044 "Got no hierarchical name access!" );
1045
1046 }
1047 }
1048 catch ( RuntimeException & )
1049 {
1050 }
1051 catch ( Exception & )
1052 {
1053 }
1054 }
1055
1056 return it->second;
1057 }
1058
findJarFileForPath(const rtl::OUString & jar,const rtl::OUString & Language,const rtl::OUString & path,rtl::OUString * o_pExtensionPath,rtl::OUString * o_pExtensionRegistryPath)1059 Reference< XHierarchicalNameAccess > Databases::findJarFileForPath
1060 ( const rtl::OUString& jar, const rtl::OUString& Language,
1061 const rtl::OUString& path, rtl::OUString* o_pExtensionPath,
1062 rtl::OUString* o_pExtensionRegistryPath )
1063 {
1064 Reference< XHierarchicalNameAccess > xNA;
1065 if( ! jar.getLength() ||
1066 ! Language.getLength() )
1067 {
1068 return xNA;
1069 }
1070
1071 JarFileIterator aJarFileIt( m_xContext, *this, jar, Language );
1072 Reference< XHierarchicalNameAccess > xTestNA;
1073 Reference< deployment::XPackage > xParentPackageBundle;
1074 while( (xTestNA = aJarFileIt.nextJarFile( xParentPackageBundle, o_pExtensionPath, o_pExtensionRegistryPath )).is() )
1075 {
1076 if( xTestNA.is() && xTestNA->hasByHierarchicalName( path ) )
1077 {
1078 bool bSuccess = true;
1079 if( xParentPackageBundle.is() )
1080 {
1081 rtl::OUString aIdentifierInPath;
1082 sal_Int32 nFindSlash = path.indexOf( '/' );
1083 if( nFindSlash != -1 )
1084 aIdentifierInPath = path.copy( 0, nFindSlash );
1085
1086 beans::Optional<rtl::OUString> aIdentifierOptional = xParentPackageBundle->getIdentifier();
1087 if( aIdentifierInPath.getLength() && aIdentifierOptional.IsPresent )
1088 {
1089 rtl::OUString aUnencodedIdentifier = aIdentifierOptional.Value;
1090 rtl::OUString aIdentifier = rtl::Uri::encode( aUnencodedIdentifier,
1091 rtl_UriCharClassPchar, rtl_UriEncodeIgnoreEscapes, RTL_TEXTENCODING_UTF8 );
1092
1093 if( !aIdentifierInPath.equals( aIdentifier ) )
1094 {
1095 // path does not start with extension identifier -> ignore
1096 bSuccess = false;
1097 }
1098 }
1099 else
1100 {
1101 // No identifier -> ignore
1102 bSuccess = false;
1103 }
1104 }
1105
1106 if( bSuccess )
1107 {
1108 xNA = xTestNA;
1109 break;
1110 }
1111 }
1112 }
1113
1114 return xNA;
1115 }
1116
popupDocument(URLParameter * urlPar,char ** buffer,int * byteCount)1117 void Databases::popupDocument( URLParameter* urlPar,char **buffer,int *byteCount )
1118 {
1119 const char* pop1 =
1120 " <html> "
1121 " <head> "
1122 " <help:css-file-link xmlns:help=\"http://openoffice.org/2000/help\"/> "
1123 " </head> "
1124 " <body> "
1125 " <help:popup-cut Id=\"";
1126 const sal_Int32 l1 = strlen( pop1 );
1127
1128 const char* pop3 = "\" Eid=\"";
1129 const sal_Int32 l3 = strlen( pop3 );
1130
1131 const char* pop5 =
1132 "\" xmlns:help=\"http://openoffice.org/2000/help\"></help:popup-cut> "
1133 " </body> "
1134 " </html>";
1135 const sal_Int32 l5 = strlen( pop5 );
1136 sal_Int32 l2,l4;
1137
1138 rtl::OUString val = urlPar->get_id();
1139 rtl::OString pop2O( val.getStr(),l2 = val.getLength(),RTL_TEXTENCODING_UTF8 );
1140 const char* pop2 = pop2O.getStr();
1141
1142 val = urlPar->get_eid();
1143 rtl::OString pop4O( val.getStr(),l4 = val.getLength(),RTL_TEXTENCODING_UTF8 );
1144 const char* pop4 = pop4O.getStr();
1145
1146 (*byteCount) = l1 + l2 + l3 + l4 + l5;
1147
1148 *buffer = new char[ 1+*byteCount ];
1149
1150 rtl_copyMemory( *buffer,pop1,l1 );
1151 rtl_copyMemory( *buffer+l1,pop2,l2 );
1152 rtl_copyMemory( *buffer+(l1+l2),pop3,l3 );
1153 rtl_copyMemory( *buffer+(l1+l2+l3),pop4,l4 );
1154 rtl_copyMemory( *buffer+(l1+l2+l3+l4),pop5,l5 );
1155 (*buffer)[*byteCount] = 0;
1156 }
1157
1158
changeCSS(const rtl::OUString & newStyleSheet)1159 void Databases::changeCSS(const rtl::OUString& newStyleSheet)
1160 {
1161 m_aCSS = newStyleSheet.toAsciiLowerCase();
1162 delete[] m_pCustomCSSDoc, m_pCustomCSSDoc = 0,m_nCustomCSSDocLength = 0;
1163 }
1164
1165
1166
cascadingStylesheet(const rtl::OUString & Language,char ** buffer,int * byteCount)1167 void Databases::cascadingStylesheet( const rtl::OUString& Language,
1168 char** buffer,
1169 int* byteCount )
1170 {
1171 if( ! m_pCustomCSSDoc )
1172 {
1173 int retry = 2;
1174 bool error = true;
1175 rtl::OUString fileURL;
1176
1177 sal_Bool bHighContrastMode = sal_False;
1178 rtl::OUString aCSS( m_aCSS );
1179 if ( aCSS.compareToAscii( "default" ) == 0 )
1180 {
1181 // #i50760: "default" needs to adapt HC mode
1182 uno::Reference< awt::XToolkit > xToolkit = uno::Reference< awt::XToolkit >(
1183 ::comphelper::getProcessServiceFactory()->createInstance( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.awt.Toolkit" ) ) ), uno::UNO_QUERY );
1184 if ( xToolkit.is() )
1185 {
1186 uno::Reference< awt::XExtendedToolkit > xExtToolkit( xToolkit, uno::UNO_QUERY );
1187 if ( xExtToolkit.is() )
1188 {
1189 uno::Reference< awt::XTopWindow > xTopWindow = xExtToolkit->getActiveTopWindow();
1190 if ( xTopWindow.is() )
1191 {
1192 uno::Reference< awt::XVclWindowPeer > xVclWindowPeer( xTopWindow, uno::UNO_QUERY );
1193 if ( xVclWindowPeer.is() )
1194 {
1195 uno::Any aHCMode = xVclWindowPeer->getProperty( rtl::OUString::createFromAscii( "HighContrastMode" ) );
1196 if ( ( aHCMode >>= bHighContrastMode ) && bHighContrastMode )
1197 aCSS = rtl::OUString::createFromAscii( "highcontrastblack" );
1198 }
1199 }
1200 }
1201 }
1202 }
1203
1204 while( error && retry )
1205 {
1206
1207 if( retry == 2 )
1208 fileURL =
1209 getInstallPathAsURL() +
1210 processLang( Language ) +
1211 rtl::OUString::createFromAscii( "/" ) +
1212 aCSS +
1213 rtl::OUString::createFromAscii( ".css" );
1214 else if( retry == 1 )
1215 fileURL =
1216 getInstallPathAsURL() +
1217 aCSS +
1218 rtl::OUString::createFromAscii( ".css" );
1219
1220 osl::DirectoryItem aDirItem;
1221 osl::File aFile( fileURL );
1222 osl::FileStatus aStatus( FileStatusMask_FileSize );
1223
1224 if( osl::FileBase::E_None == osl::DirectoryItem::get( fileURL,aDirItem ) &&
1225 osl::FileBase::E_None == aFile.open( OpenFlag_Read ) &&
1226 osl::FileBase::E_None == aDirItem.getFileStatus( aStatus ) )
1227 {
1228 m_nCustomCSSDocLength = int( aStatus.getFileSize() );
1229 m_pCustomCSSDoc = new char[ 1 + m_nCustomCSSDocLength ];
1230 m_pCustomCSSDoc[ m_nCustomCSSDocLength ] = 0;
1231 sal_uInt64 a = m_nCustomCSSDocLength,b = m_nCustomCSSDocLength;
1232 aFile.read( m_pCustomCSSDoc,a,b );
1233 aFile.close();
1234 error = false;
1235 }
1236
1237 --retry;
1238 if ( !retry && error && bHighContrastMode )
1239 {
1240 // fall back to default css
1241 aCSS = rtl::OUString::createFromAscii( "default" );
1242 retry = 2;
1243 bHighContrastMode = sal_False;
1244 }
1245 }
1246
1247 if( error )
1248 {
1249 m_nCustomCSSDocLength = 0;
1250 m_pCustomCSSDoc = new char[ 1 ]; // Initialize with 1 to avoid gcc compiler warning
1251 }
1252 }
1253
1254 *byteCount = m_nCustomCSSDocLength;
1255 *buffer = new char[ 1 + *byteCount ];
1256 (*buffer)[*byteCount] = 0;
1257 rtl_copyMemory( *buffer,m_pCustomCSSDoc,m_nCustomCSSDocLength );
1258
1259 }
1260
1261
setActiveText(const rtl::OUString & Module,const rtl::OUString & Language,const rtl::OUString & Id,char ** buffer,int * byteCount)1262 void Databases::setActiveText( const rtl::OUString& Module,
1263 const rtl::OUString& Language,
1264 const rtl::OUString& Id,
1265 char** buffer,
1266 int* byteCount )
1267 {
1268 DataBaseIterator aDbIt( m_xContext, *this, Module, Language, true );
1269
1270 // #i84550 Cache information about failed ids
1271 rtl::OString id( Id.getStr(),Id.getLength(),RTL_TEXTENCODING_UTF8 );
1272 EmptyActiveTextSet::iterator it = m_aEmptyActiveTextSet.find( id );
1273 bool bFoundAsEmpty = ( it != m_aEmptyActiveTextSet.end() );
1274 helpdatafileproxy::HDFData aHDFData;
1275
1276 int nSize = 0;
1277 const sal_Char* pData = NULL;
1278
1279 bool bSuccess = false;
1280 if( !bFoundAsEmpty )
1281 {
1282 helpdatafileproxy::Hdf* pHdf = 0;
1283 while( !bSuccess && (pHdf = aDbIt.nextHdf()) != NULL )
1284 {
1285 bSuccess = pHdf->getValueForKey( id, aHDFData );
1286 nSize = aHDFData.getSize();
1287 pData = aHDFData.getData();
1288 }
1289 }
1290
1291 if( bSuccess )
1292 {
1293 // ensure existence of tmp after for
1294 rtl::OString tmp;
1295 for( int i = 0; i < nSize; ++i )
1296 if( pData[i] == '%' || pData[i] == '$' )
1297 {
1298 // need of replacement
1299 rtl::OUString temp = rtl::OUString( pData, nSize, RTL_TEXTENCODING_UTF8 );
1300 replaceName( temp );
1301 tmp = rtl::OString( temp.getStr(),
1302 temp.getLength(),
1303 RTL_TEXTENCODING_UTF8 );
1304 nSize = tmp.getLength();
1305 pData = tmp.getStr();
1306 break;
1307 }
1308
1309 *byteCount = nSize;
1310 *buffer = new char[ 1 + nSize ];
1311 (*buffer)[nSize] = 0;
1312 rtl_copyMemory( *buffer, pData, nSize );
1313 }
1314 else
1315 {
1316 *byteCount = 0;
1317 *buffer = new char[1]; // Initialize with 1 to avoid compiler warnings
1318 if( !bFoundAsEmpty )
1319 m_aEmptyActiveTextSet.insert( id );
1320 }
1321 }
1322
1323
setInstallPath(const rtl::OUString & aInstDir)1324 void Databases::setInstallPath( const rtl::OUString& aInstDir )
1325 {
1326 osl::MutexGuard aGuard( m_aMutex );
1327
1328 osl::FileBase::getFileURLFromSystemPath( aInstDir,m_aInstallDirectory );
1329 //TODO: check returned error code
1330
1331 if( m_aInstallDirectory.lastIndexOf( sal_Unicode( '/' ) ) != m_aInstallDirectory.getLength() - 1 )
1332 m_aInstallDirectory += rtl::OUString::createFromAscii( "/" );
1333
1334 m_aInstallDirectoryWithoutEncoding = rtl::Uri::decode( m_aInstallDirectory,
1335 rtl_UriDecodeWithCharset,
1336 RTL_TEXTENCODING_UTF8 );
1337 }
1338
1339
1340 //===================================================================
1341 // class ExtensionIteratorBase
1342
1343 ExtensionHelpExistanceMap ExtensionIteratorBase::aHelpExistanceMap;
1344
ExtensionIteratorBase(Reference<XComponentContext> xContext,Databases & rDatabases,const rtl::OUString & aInitialModule,const rtl::OUString & aLanguage)1345 ExtensionIteratorBase::ExtensionIteratorBase( Reference< XComponentContext > xContext,
1346 Databases& rDatabases, const rtl::OUString& aInitialModule, const rtl::OUString& aLanguage )
1347 : m_xContext( xContext )
1348 , m_rDatabases( rDatabases )
1349 , m_eState( INITIAL_MODULE )
1350 , m_aInitialModule( aInitialModule )
1351 , m_aLanguage( aLanguage )
1352 {
1353 init();
1354 }
1355
ExtensionIteratorBase(Databases & rDatabases,const rtl::OUString & aInitialModule,const rtl::OUString & aLanguage)1356 ExtensionIteratorBase::ExtensionIteratorBase( Databases& rDatabases,
1357 const rtl::OUString& aInitialModule, const rtl::OUString& aLanguage )
1358 : m_rDatabases( rDatabases )
1359 , m_eState( INITIAL_MODULE )
1360 , m_aInitialModule( aInitialModule )
1361 , m_aLanguage( aLanguage )
1362 {
1363 init();
1364 }
1365
init()1366 void ExtensionIteratorBase::init()
1367 {
1368 if( !m_xContext.is() )
1369 {
1370 Reference< XMultiServiceFactory > xFactory = comphelper::getProcessServiceFactory();
1371 Reference< XPropertySet > xProps( xFactory, UNO_QUERY );
1372 OSL_ASSERT( xProps.is() );
1373 if (xProps.is())
1374 {
1375 xProps->getPropertyValue(
1376 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("DefaultContext") ) ) >>= m_xContext;
1377 OSL_ASSERT( m_xContext.is() );
1378 }
1379 }
1380 if( !m_xContext.is() )
1381 {
1382 throw RuntimeException(
1383 ::rtl::OUString::createFromAscii( "ExtensionIteratorBase::init(), no XComponentContext" ),
1384 Reference< XInterface >() );
1385 }
1386
1387 Reference< XMultiComponentFactory > xSMgr( m_xContext->getServiceManager(), UNO_QUERY );
1388 m_xSFA = Reference< ucb::XSimpleFileAccess >(
1389 xSMgr->createInstanceWithContext( rtl::OUString::createFromAscii( "com.sun.star.ucb.SimpleFileAccess" ),
1390 m_xContext ), UNO_QUERY_THROW );
1391
1392 m_bUserPackagesLoaded = false;
1393 m_bSharedPackagesLoaded = false;
1394 m_bBundledPackagesLoaded = false;
1395 m_iUserPackage = 0;
1396 m_iSharedPackage = 0;
1397 m_iBundledPackage = 0;
1398 }
1399
implGetHelpPackageFromPackage(Reference<deployment::XPackage> xPackage,Reference<deployment::XPackage> & o_xParentPackageBundle)1400 Reference< deployment::XPackage > ExtensionIteratorBase::implGetHelpPackageFromPackage
1401 ( Reference< deployment::XPackage > xPackage, Reference< deployment::XPackage >& o_xParentPackageBundle )
1402 {
1403 o_xParentPackageBundle.clear();
1404
1405 Reference< deployment::XPackage > xHelpPackage;
1406 if( !xPackage.is() )
1407 return xHelpPackage;
1408
1409 // #i84550 Cache information about help content in extension
1410 rtl::OUString aExtensionPath = xPackage->getURL();
1411 ExtensionHelpExistanceMap::iterator it = aHelpExistanceMap.find( aExtensionPath );
1412 bool bFound = ( it != aHelpExistanceMap.end() );
1413 bool bHasHelp = bFound ? it->second : false;
1414 if( bFound && !bHasHelp )
1415 return xHelpPackage;
1416
1417 // Check if parent package is registered
1418 beans::Optional< beans::Ambiguous<sal_Bool> > option( xPackage->isRegistered
1419 ( Reference<task::XAbortChannel>(), Reference<ucb::XCommandEnvironment>() ) );
1420 bool bRegistered = false;
1421 if( option.IsPresent )
1422 {
1423 beans::Ambiguous<sal_Bool> const & reg = option.Value;
1424 if( !reg.IsAmbiguous && reg.Value )
1425 bRegistered = true;
1426 }
1427 if( bRegistered )
1428 {
1429 if( xPackage->isBundle() )
1430 {
1431 Sequence< Reference< deployment::XPackage > > aPkgSeq = xPackage->getBundle
1432 ( Reference<task::XAbortChannel>(), Reference<ucb::XCommandEnvironment>() );
1433 sal_Int32 nPkgCount = aPkgSeq.getLength();
1434 const Reference< deployment::XPackage >* pSeq = aPkgSeq.getConstArray();
1435 for( sal_Int32 iPkg = 0 ; iPkg < nPkgCount ; ++iPkg )
1436 {
1437 const Reference< deployment::XPackage > xSubPkg = pSeq[ iPkg ];
1438 const Reference< deployment::XPackageTypeInfo > xPackageTypeInfo = xSubPkg->getPackageType();
1439 rtl::OUString aMediaType = xPackageTypeInfo->getMediaType();
1440 if( aMediaType.equals( aHelpMediaType ) )
1441 {
1442 xHelpPackage = xSubPkg;
1443 o_xParentPackageBundle = xPackage;
1444 break;
1445 }
1446 }
1447 }
1448 else
1449 {
1450 const Reference< deployment::XPackageTypeInfo > xPackageTypeInfo = xPackage->getPackageType();
1451 rtl::OUString aMediaType = xPackageTypeInfo->getMediaType();
1452 if( aMediaType.equals( aHelpMediaType ) )
1453 xHelpPackage = xPackage;
1454 }
1455 }
1456
1457 if( !bFound )
1458 aHelpExistanceMap[ aExtensionPath ] = xHelpPackage.is();
1459
1460 return xHelpPackage;
1461 }
1462
implGetNextUserHelpPackage(Reference<deployment::XPackage> & o_xParentPackageBundle)1463 Reference< deployment::XPackage > ExtensionIteratorBase::implGetNextUserHelpPackage
1464 ( Reference< deployment::XPackage >& o_xParentPackageBundle )
1465 {
1466 Reference< deployment::XPackage > xHelpPackage;
1467
1468 if( !m_bUserPackagesLoaded )
1469 {
1470 Reference< XExtensionManager > xExtensionManager = ExtensionManager::get(m_xContext);
1471 m_aUserPackagesSeq = xExtensionManager->getDeployedExtensions
1472 ( rtl::OUString::createFromAscii("user"), Reference< task::XAbortChannel >(), Reference< ucb::XCommandEnvironment >() );
1473 m_bUserPackagesLoaded = true;
1474 }
1475
1476 if( m_iUserPackage == m_aUserPackagesSeq.getLength() )
1477 {
1478 m_eState = SHARED_EXTENSIONS; // Later: SHARED_MODULE
1479 }
1480 else
1481 {
1482 const Reference< deployment::XPackage >* pUserPackages = m_aUserPackagesSeq.getConstArray();
1483 Reference< deployment::XPackage > xPackage = pUserPackages[ m_iUserPackage++ ];
1484 VOS_ENSURE( xPackage.is(), "ExtensionIteratorBase::implGetNextUserHelpPackage(): Invalid package" );
1485 xHelpPackage = implGetHelpPackageFromPackage( xPackage, o_xParentPackageBundle );
1486 }
1487
1488 return xHelpPackage;
1489 }
1490
implGetNextSharedHelpPackage(Reference<deployment::XPackage> & o_xParentPackageBundle)1491 Reference< deployment::XPackage > ExtensionIteratorBase::implGetNextSharedHelpPackage
1492 ( Reference< deployment::XPackage >& o_xParentPackageBundle )
1493 {
1494 Reference< deployment::XPackage > xHelpPackage;
1495
1496 if( !m_bSharedPackagesLoaded )
1497 {
1498 Reference< XExtensionManager > xExtensionManager = ExtensionManager::get(m_xContext);
1499 m_aSharedPackagesSeq = xExtensionManager->getDeployedExtensions
1500 ( rtl::OUString::createFromAscii("shared"), Reference< task::XAbortChannel >(), Reference< ucb::XCommandEnvironment >() );
1501 m_bSharedPackagesLoaded = true;
1502 }
1503
1504 if( m_iSharedPackage == m_aSharedPackagesSeq.getLength() )
1505 {
1506 m_eState = BUNDLED_EXTENSIONS;
1507 }
1508 else
1509 {
1510 const Reference< deployment::XPackage >* pSharedPackages = m_aSharedPackagesSeq.getConstArray();
1511 Reference< deployment::XPackage > xPackage = pSharedPackages[ m_iSharedPackage++ ];
1512 VOS_ENSURE( xPackage.is(), "ExtensionIteratorBase::implGetNextSharedHelpPackage(): Invalid package" );
1513 xHelpPackage = implGetHelpPackageFromPackage( xPackage, o_xParentPackageBundle );
1514 }
1515
1516 return xHelpPackage;
1517 }
1518
implGetNextBundledHelpPackage(Reference<deployment::XPackage> & o_xParentPackageBundle)1519 Reference< deployment::XPackage > ExtensionIteratorBase::implGetNextBundledHelpPackage
1520 ( Reference< deployment::XPackage >& o_xParentPackageBundle )
1521 {
1522 Reference< deployment::XPackage > xHelpPackage;
1523
1524 if( !m_bBundledPackagesLoaded )
1525 {
1526 Reference< XExtensionManager > xExtensionManager = ExtensionManager::get(m_xContext);
1527 m_aBundledPackagesSeq = xExtensionManager->getDeployedExtensions
1528 ( rtl::OUString::createFromAscii("bundled"), Reference< task::XAbortChannel >(), Reference< ucb::XCommandEnvironment >() );
1529 m_bBundledPackagesLoaded = true;
1530 }
1531
1532 if( m_iBundledPackage == m_aBundledPackagesSeq.getLength() )
1533 {
1534 m_eState = END_REACHED;
1535 }
1536 else
1537 {
1538 const Reference< deployment::XPackage >* pBundledPackages =
1539 m_aBundledPackagesSeq.getConstArray();
1540 Reference< deployment::XPackage > xPackage = pBundledPackages[ m_iBundledPackage++ ];
1541 VOS_ENSURE( xPackage.is(), "ExtensionIteratorBase::implGetNextBundledHelpPackage(): Invalid package" );
1542 xHelpPackage = implGetHelpPackageFromPackage( xPackage, o_xParentPackageBundle );
1543 }
1544
1545 return xHelpPackage;
1546 }
1547
implGetFileFromPackage(const rtl::OUString & rFileExtension,Reference<deployment::XPackage> xPackage)1548 rtl::OUString ExtensionIteratorBase::implGetFileFromPackage(
1549 const rtl::OUString& rFileExtension, Reference< deployment::XPackage > xPackage )
1550 {
1551 // No extension -> search for pure language folder
1552 bool bLangFolderOnly = (rFileExtension.getLength() == 0);
1553
1554 rtl::OUString aFile;
1555 rtl::OUString aLanguage = m_aLanguage;
1556 for( sal_Int32 iPass = 0 ; iPass < 2 ; ++iPass )
1557 {
1558 rtl::OUStringBuffer aStrBuf;
1559 aStrBuf.append( xPackage->getRegistrationDataURL().Value);
1560 aStrBuf.append( aSlash );
1561 aStrBuf.append( aLanguage );
1562 if( !bLangFolderOnly )
1563 {
1564 aStrBuf.append( aSlash );
1565 aStrBuf.append( aHelpFilesBaseName );
1566 aStrBuf.append( rFileExtension );
1567 }
1568
1569 aFile = m_rDatabases.expandURL( aStrBuf.makeStringAndClear() );
1570 if( iPass == 0 )
1571 {
1572 if( m_xSFA->exists( aFile ) )
1573 break;
1574
1575 ::std::vector< ::rtl::OUString > av;
1576 implGetLanguageVectorFromPackage( av, xPackage );
1577 ::std::vector< ::rtl::OUString >::const_iterator pFound = av.end();
1578 try
1579 {
1580 pFound = ::comphelper::Locale::getFallback( av, m_aLanguage );
1581 }
1582 catch( ::comphelper::Locale::MalFormedLocaleException& )
1583 {}
1584 if( pFound != av.end() )
1585 aLanguage = *pFound;
1586 }
1587 }
1588 return aFile;
1589 }
1590
isLetter(sal_Unicode c)1591 inline bool isLetter( sal_Unicode c )
1592 {
1593 bool bLetter = ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'));
1594 return bLetter;
1595 }
1596
implGetLanguageVectorFromPackage(::std::vector<::rtl::OUString> & rv,com::sun::star::uno::Reference<com::sun::star::deployment::XPackage> xPackage)1597 void ExtensionIteratorBase::implGetLanguageVectorFromPackage( ::std::vector< ::rtl::OUString > &rv,
1598 com::sun::star::uno::Reference< com::sun::star::deployment::XPackage > xPackage )
1599 {
1600 rv.clear();
1601 rtl::OUString aExtensionPath = xPackage->getURL();
1602 Sequence< rtl::OUString > aEntrySeq = m_xSFA->getFolderContents( aExtensionPath, true );
1603
1604 const rtl::OUString* pSeq = aEntrySeq.getConstArray();
1605 sal_Int32 nCount = aEntrySeq.getLength();
1606 for( sal_Int32 i = 0 ; i < nCount ; ++i )
1607 {
1608 rtl::OUString aEntry = pSeq[i];
1609 if( m_xSFA->isFolder( aEntry ) )
1610 {
1611 sal_Int32 nLastSlash = aEntry.lastIndexOf( '/' );
1612 if( nLastSlash != -1 )
1613 {
1614 rtl::OUString aPureEntry = aEntry.copy( nLastSlash + 1 );
1615
1616 // Check language sceme
1617 int nLen = aPureEntry.getLength();
1618 const sal_Unicode* pc = aPureEntry.getStr();
1619 bool bStartCanBeLanguage = ( nLen >= 2 && isLetter( pc[0] ) && isLetter( pc[1] ) );
1620 bool bIsLanguage = bStartCanBeLanguage &&
1621 ( nLen == 2 || (nLen == 5 && pc[2] == '-' && isLetter( pc[3] ) && isLetter( pc[4] )) );
1622 if( bIsLanguage )
1623 rv.push_back( aPureEntry );
1624 }
1625 }
1626 }
1627 }
1628
1629
1630 //===================================================================
1631 // class DataBaseIterator
1632
nextHdf(rtl::OUString * o_pExtensionPath,rtl::OUString * o_pExtensionRegistryPath)1633 helpdatafileproxy::Hdf* DataBaseIterator::nextHdf( rtl::OUString* o_pExtensionPath, rtl::OUString* o_pExtensionRegistryPath )
1634 {
1635 helpdatafileproxy::Hdf* pRetHdf = NULL;
1636
1637 while( !pRetHdf && m_eState != END_REACHED )
1638 {
1639 switch( m_eState )
1640 {
1641 case INITIAL_MODULE:
1642 pRetHdf = m_rDatabases.getHelpDataFile( m_aInitialModule, m_aLanguage, m_bHelpText );
1643 m_eState = USER_EXTENSIONS; // Later: SHARED_MODULE
1644 break;
1645
1646 // Later:
1647 //case SHARED_MODULE
1648 //...
1649
1650 case USER_EXTENSIONS:
1651 {
1652 Reference< deployment::XPackage > xParentPackageBundle;
1653 Reference< deployment::XPackage > xHelpPackage = implGetNextUserHelpPackage( xParentPackageBundle );
1654 if( !xHelpPackage.is() )
1655 break;
1656 pRetHdf = implGetHdfFromPackage( xHelpPackage, o_pExtensionPath, o_pExtensionRegistryPath );
1657 break;
1658 }
1659
1660 case SHARED_EXTENSIONS:
1661 {
1662 Reference< deployment::XPackage > xParentPackageBundle;
1663 Reference< deployment::XPackage > xHelpPackage = implGetNextSharedHelpPackage( xParentPackageBundle );
1664 if( !xHelpPackage.is() )
1665 break;
1666
1667 pRetHdf = implGetHdfFromPackage( xHelpPackage, o_pExtensionPath, o_pExtensionRegistryPath );
1668 break;
1669 }
1670
1671 case BUNDLED_EXTENSIONS:
1672 {
1673 Reference< deployment::XPackage > xParentPackageBundle;
1674 Reference< deployment::XPackage > xHelpPackage = implGetNextBundledHelpPackage( xParentPackageBundle );
1675 if( !xHelpPackage.is() )
1676 break;
1677
1678 pRetHdf = implGetHdfFromPackage( xHelpPackage, o_pExtensionPath, o_pExtensionRegistryPath );
1679 break;
1680 }
1681
1682 case END_REACHED:
1683 VOS_ENSURE( false, "DataBaseIterator::nextDb(): Invalid case END_REACHED" );
1684 break;
1685 }
1686 }
1687
1688 return pRetHdf;
1689 }
1690
implGetHdfFromPackage(Reference<deployment::XPackage> xPackage,rtl::OUString * o_pExtensionPath,rtl::OUString * o_pExtensionRegistryPath)1691 helpdatafileproxy::Hdf* DataBaseIterator::implGetHdfFromPackage( Reference< deployment::XPackage > xPackage,
1692 rtl::OUString* o_pExtensionPath, rtl::OUString* o_pExtensionRegistryPath )
1693 {
1694
1695 beans::Optional< ::rtl::OUString> optRegData;
1696 try
1697 {
1698 optRegData = xPackage->getRegistrationDataURL();
1699 }
1700 catch ( deployment::ExtensionRemovedException&)
1701 {
1702 return NULL;
1703 }
1704
1705 helpdatafileproxy::Hdf* pRetHdf = NULL;
1706 if (optRegData.IsPresent && optRegData.Value.getLength() > 0)
1707 {
1708 rtl::OUString aRegDataUrl(optRegData.Value);
1709 aRegDataUrl += aSlash;
1710
1711 rtl::OUString aUsedLanguage = m_aLanguage;
1712 pRetHdf = m_rDatabases.getHelpDataFile(
1713 aHelpFilesBaseName, aUsedLanguage, m_bHelpText, &aRegDataUrl);
1714
1715 // Language fallback
1716 if( !pRetHdf )
1717 {
1718 ::std::vector< ::rtl::OUString > av;
1719 implGetLanguageVectorFromPackage( av, xPackage );
1720 ::std::vector< ::rtl::OUString >::const_iterator pFound = av.end();
1721 try
1722 {
1723 pFound = ::comphelper::Locale::getFallback( av, m_aLanguage );
1724 }
1725 catch( ::comphelper::Locale::MalFormedLocaleException& )
1726 {}
1727 if( pFound != av.end() )
1728 {
1729 aUsedLanguage = *pFound;
1730 pRetHdf = m_rDatabases.getHelpDataFile(
1731 aHelpFilesBaseName, aUsedLanguage, m_bHelpText, &aRegDataUrl);
1732 }
1733 }
1734
1735 if( o_pExtensionPath )
1736 *o_pExtensionPath = aRegDataUrl + aUsedLanguage;
1737
1738 if( o_pExtensionRegistryPath )
1739 *o_pExtensionRegistryPath = xPackage->getURL() + aSlash + aUsedLanguage;
1740 }
1741
1742 return pRetHdf;
1743 }
1744
1745
1746 //===================================================================
1747 // class KeyDataBaseFileIterator
1748
1749 //returns a file URL
nextDbFile(bool & o_rbExtension)1750 rtl::OUString KeyDataBaseFileIterator::nextDbFile( bool& o_rbExtension )
1751 {
1752 rtl::OUString aRetFile;
1753
1754 while( !aRetFile.getLength() && m_eState != END_REACHED )
1755 {
1756 switch( m_eState )
1757 {
1758 case INITIAL_MODULE:
1759 aRetFile =
1760 m_rDatabases.getInstallPathAsURL() +
1761 m_rDatabases.processLang( m_aLanguage ) + aSlash + m_aInitialModule +
1762 rtl::OUString::createFromAscii( ".key" );
1763
1764 o_rbExtension = false;
1765
1766 m_eState = USER_EXTENSIONS; // Later: SHARED_MODULE
1767 break;
1768
1769 // Later:
1770 //case SHARED_MODULE
1771 //...
1772
1773 case USER_EXTENSIONS:
1774 {
1775 Reference< deployment::XPackage > xParentPackageBundle;
1776 Reference< deployment::XPackage > xHelpPackage = implGetNextUserHelpPackage( xParentPackageBundle );
1777 if( !xHelpPackage.is() )
1778 break;
1779
1780 aRetFile = implGetDbFileFromPackage( xHelpPackage );
1781 o_rbExtension = true;
1782 break;
1783 }
1784
1785 case SHARED_EXTENSIONS:
1786 {
1787 Reference< deployment::XPackage > xParentPackageBundle;
1788 Reference< deployment::XPackage > xHelpPackage = implGetNextSharedHelpPackage( xParentPackageBundle );
1789 if( !xHelpPackage.is() )
1790 break;
1791
1792 aRetFile = implGetDbFileFromPackage( xHelpPackage );
1793 o_rbExtension = true;
1794 break;
1795 }
1796
1797 case BUNDLED_EXTENSIONS:
1798 {
1799 Reference< deployment::XPackage > xParentPackageBundle;
1800 Reference< deployment::XPackage > xHelpPackage = implGetNextBundledHelpPackage( xParentPackageBundle );
1801 if( !xHelpPackage.is() )
1802 break;
1803
1804 aRetFile = implGetDbFileFromPackage( xHelpPackage );
1805 o_rbExtension = true;
1806 break;
1807 }
1808
1809 case END_REACHED:
1810 VOS_ENSURE( false, "DataBaseIterator::nextDbFile(): Invalid case END_REACHED" );
1811 break;
1812 }
1813 }
1814
1815 return aRetFile;
1816 }
1817
1818 //Returns a file URL, that does not contain macros
implGetDbFileFromPackage(Reference<deployment::XPackage> xPackage)1819 rtl::OUString KeyDataBaseFileIterator::implGetDbFileFromPackage
1820 ( Reference< deployment::XPackage > xPackage )
1821 {
1822 rtl::OUString aExpandedURL =
1823 implGetFileFromPackage( rtl::OUString::createFromAscii( ".key" ), xPackage );
1824
1825 return aExpandedURL;
1826 }
1827
1828
1829 //===================================================================
1830 // class JarFileIterator
1831
nextJarFile(Reference<deployment::XPackage> & o_xParentPackageBundle,rtl::OUString * o_pExtensionPath,rtl::OUString * o_pExtensionRegistryPath)1832 Reference< XHierarchicalNameAccess > JarFileIterator::nextJarFile
1833 ( Reference< deployment::XPackage >& o_xParentPackageBundle,
1834 rtl::OUString* o_pExtensionPath, rtl::OUString* o_pExtensionRegistryPath )
1835 {
1836 Reference< XHierarchicalNameAccess > xNA;
1837
1838 while( !xNA.is() && m_eState != END_REACHED )
1839 {
1840 switch( m_eState )
1841 {
1842 case INITIAL_MODULE:
1843 xNA = m_rDatabases.jarFile( m_aInitialModule, m_aLanguage );
1844 m_eState = USER_EXTENSIONS; // Later: SHARED_MODULE
1845 break;
1846
1847 // Later:
1848 //case SHARED_MODULE
1849 //...
1850
1851 case USER_EXTENSIONS:
1852 {
1853 Reference< deployment::XPackage > xHelpPackage = implGetNextUserHelpPackage( o_xParentPackageBundle );
1854 if( !xHelpPackage.is() )
1855 break;
1856
1857 xNA = implGetJarFromPackage( xHelpPackage, o_pExtensionPath, o_pExtensionRegistryPath );
1858 break;
1859 }
1860
1861 case SHARED_EXTENSIONS:
1862 {
1863 Reference< deployment::XPackage > xHelpPackage = implGetNextSharedHelpPackage( o_xParentPackageBundle );
1864 if( !xHelpPackage.is() )
1865 break;
1866
1867 xNA = implGetJarFromPackage( xHelpPackage, o_pExtensionPath, o_pExtensionRegistryPath );
1868 break;
1869 }
1870
1871 case BUNDLED_EXTENSIONS:
1872 {
1873 Reference< deployment::XPackage > xHelpPackage = implGetNextBundledHelpPackage( o_xParentPackageBundle );
1874 if( !xHelpPackage.is() )
1875 break;
1876
1877 xNA = implGetJarFromPackage( xHelpPackage, o_pExtensionPath, o_pExtensionRegistryPath );
1878 break;
1879 }
1880
1881 case END_REACHED:
1882 VOS_ENSURE( false, "JarFileIterator::nextJarFile(): Invalid case END_REACHED" );
1883 break;
1884 }
1885 }
1886
1887 return xNA;
1888 }
1889
implGetJarFromPackage(Reference<deployment::XPackage> xPackage,rtl::OUString * o_pExtensionPath,rtl::OUString * o_pExtensionRegistryPath)1890 Reference< XHierarchicalNameAccess > JarFileIterator::implGetJarFromPackage
1891 ( Reference< deployment::XPackage > xPackage, rtl::OUString* o_pExtensionPath, rtl::OUString* o_pExtensionRegistryPath )
1892 {
1893 Reference< XHierarchicalNameAccess > xNA;
1894
1895 rtl::OUString zipFile =
1896 implGetFileFromPackage( rtl::OUString::createFromAscii( ".jar" ), xPackage );
1897
1898 try
1899 {
1900 Sequence< Any > aArguments( 2 );
1901 aArguments[ 0 ] <<= zipFile;
1902
1903 // let ZipPackage be used ( no manifest.xml is required )
1904 beans::NamedValue aArg;
1905 aArg.Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "StorageFormat" ) );
1906 aArg.Value <<= ZIP_STORAGE_FORMAT_STRING;
1907 aArguments[ 1 ] <<= aArg;
1908
1909 Reference< XMultiComponentFactory >xSMgr( m_xContext->getServiceManager(), UNO_QUERY );
1910 Reference< XInterface > xIfc
1911 = xSMgr->createInstanceWithArgumentsAndContext(
1912 rtl::OUString::createFromAscii(
1913 "com.sun.star.packages.comp.ZipPackage" ),
1914 aArguments, m_xContext );
1915
1916 if ( xIfc.is() )
1917 {
1918 xNA = Reference< XHierarchicalNameAccess >( xIfc, UNO_QUERY );
1919
1920 VOS_ENSURE( xNA.is(),
1921 "JarFileIterator::implGetJarFromPackage() - "
1922 "Got no hierarchical name access!" );
1923 }
1924 }
1925 catch ( RuntimeException & )
1926 {}
1927 catch ( Exception & )
1928 {}
1929
1930 if( xNA.is() && o_pExtensionPath != NULL )
1931 {
1932 // Extract path including language from file name
1933 sal_Int32 nLastSlash = zipFile.lastIndexOf( '/' );
1934 if( nLastSlash != -1 )
1935 *o_pExtensionPath = zipFile.copy( 0, nLastSlash );
1936
1937 if( o_pExtensionRegistryPath != NULL )
1938 {
1939 rtl::OUString& rPath = *o_pExtensionPath;
1940 sal_Int32 nLastSlashInPath = rPath.lastIndexOf( '/', rPath.getLength() - 1 );
1941
1942 *o_pExtensionRegistryPath = xPackage->getURL();
1943 *o_pExtensionRegistryPath += rPath.copy( nLastSlashInPath);
1944 }
1945 }
1946
1947 return xNA;
1948 }
1949
1950
1951 //===================================================================
1952 // class IndexFolderIterator
1953
nextIndexFolder(bool & o_rbExtension,bool & o_rbTemporary)1954 rtl::OUString IndexFolderIterator::nextIndexFolder( bool& o_rbExtension, bool& o_rbTemporary )
1955 {
1956 rtl::OUString aIndexFolder;
1957
1958 while( !aIndexFolder.getLength() && m_eState != END_REACHED )
1959 {
1960 switch( m_eState )
1961 {
1962 case INITIAL_MODULE:
1963 aIndexFolder =
1964 m_rDatabases.getInstallPathAsURL() +
1965 m_rDatabases.processLang( m_aLanguage ) + aSlash + m_aInitialModule +
1966 rtl::OUString::createFromAscii( ".idxl" );
1967
1968 o_rbTemporary = false;
1969 o_rbExtension = false;
1970
1971 m_eState = USER_EXTENSIONS; // Later: SHARED_MODULE
1972 break;
1973
1974 // Later:
1975 //case SHARED_MODULE
1976 //...
1977
1978 case USER_EXTENSIONS:
1979 {
1980 Reference< deployment::XPackage > xParentPackageBundle;
1981 Reference< deployment::XPackage > xHelpPackage = implGetNextUserHelpPackage( xParentPackageBundle );
1982 if( !xHelpPackage.is() )
1983 break;
1984
1985 aIndexFolder = implGetIndexFolderFromPackage( o_rbTemporary, xHelpPackage );
1986 o_rbExtension = true;
1987 break;
1988 }
1989
1990 case SHARED_EXTENSIONS:
1991 {
1992 Reference< deployment::XPackage > xParentPackageBundle;
1993 Reference< deployment::XPackage > xHelpPackage = implGetNextSharedHelpPackage( xParentPackageBundle );
1994 if( !xHelpPackage.is() )
1995 break;
1996
1997 aIndexFolder = implGetIndexFolderFromPackage( o_rbTemporary, xHelpPackage );
1998 o_rbExtension = true;
1999 break;
2000 }
2001
2002 case BUNDLED_EXTENSIONS:
2003 {
2004 Reference< deployment::XPackage > xParentPackageBundle;
2005 Reference< deployment::XPackage > xHelpPackage = implGetNextBundledHelpPackage( xParentPackageBundle );
2006 if( !xHelpPackage.is() )
2007 break;
2008
2009 aIndexFolder = implGetIndexFolderFromPackage( o_rbTemporary, xHelpPackage );
2010 o_rbExtension = true;
2011 break;
2012 }
2013
2014 case END_REACHED:
2015 VOS_ENSURE( false, "IndexFolderIterator::nextIndexFolder(): Invalid case END_REACHED" );
2016 break;
2017 }
2018 }
2019
2020 return aIndexFolder;
2021 }
2022
implGetIndexFolderFromPackage(bool & o_rbTemporary,Reference<deployment::XPackage> xPackage)2023 rtl::OUString IndexFolderIterator::implGetIndexFolderFromPackage( bool& o_rbTemporary, Reference< deployment::XPackage > xPackage )
2024 {
2025 rtl::OUString aIndexFolder =
2026 implGetFileFromPackage( rtl::OUString::createFromAscii( ".idxl" ), xPackage );
2027
2028 o_rbTemporary = false;
2029 if( !m_xSFA->isFolder( aIndexFolder ) )
2030 {
2031 // i98680: Missing index? Try to generate now
2032 rtl::OUString aLangURL = implGetFileFromPackage( rtl::OUString(), xPackage );
2033 if( m_xSFA->isFolder( aLangURL ) )
2034 {
2035 // Test write access (shared extension may be read only)
2036 bool bIsWriteAccess = false;
2037 try
2038 {
2039 rtl::OUString aCreateTestFolder = aLangURL + rtl::OUString::createFromAscii( "CreateTestFolder" );
2040 m_xSFA->createFolder( aCreateTestFolder );
2041 if( m_xSFA->isFolder( aCreateTestFolder ) )
2042 bIsWriteAccess = true;
2043
2044 m_xSFA->kill( aCreateTestFolder );
2045 }
2046 catch (Exception &)
2047 {}
2048
2049 // TEST
2050 //bIsWriteAccess = false;
2051
2052 Reference< script::XInvocation > xInvocation;
2053 Reference< XMultiComponentFactory >xSMgr( m_xContext->getServiceManager(), UNO_QUERY );
2054 try
2055 {
2056 xInvocation = Reference< script::XInvocation >(
2057 m_xContext->getServiceManager()->createInstanceWithContext( rtl::OUString::createFromAscii(
2058 "com.sun.star.help.HelpIndexer" ), m_xContext ) , UNO_QUERY );
2059
2060 if( xInvocation.is() )
2061 {
2062 Sequence<uno::Any> aParamsSeq( bIsWriteAccess ? 6 : 8 );
2063
2064 aParamsSeq[0] = uno::makeAny( rtl::OUString::createFromAscii( "-lang" ) );
2065
2066 rtl::OUString aLang;
2067 sal_Int32 nLastSlash = aLangURL.lastIndexOf( '/' );
2068 if( nLastSlash != -1 )
2069 aLang = aLangURL.copy( nLastSlash + 1 );
2070 else
2071 aLang = rtl::OUString::createFromAscii( "en" );
2072 aParamsSeq[1] = uno::makeAny( aLang );
2073
2074 aParamsSeq[2] = uno::makeAny( rtl::OUString::createFromAscii( "-mod" ) );
2075 aParamsSeq[3] = uno::makeAny( rtl::OUString::createFromAscii( "help" ) );
2076
2077 rtl::OUString aZipDir = aLangURL;
2078 if( !bIsWriteAccess )
2079 {
2080 rtl::OUString aTempFileURL;
2081 ::osl::FileBase::RC eErr = ::osl::File::createTempFile( 0, 0, &aTempFileURL );
2082 if( eErr == ::osl::FileBase::E_None )
2083 {
2084 rtl::OUString aTempDirURL = aTempFileURL;
2085 try
2086 {
2087 m_xSFA->kill( aTempDirURL );
2088 }
2089 catch (Exception &)
2090 {}
2091 m_xSFA->createFolder( aTempDirURL );
2092
2093 aZipDir = aTempDirURL;
2094 o_rbTemporary = true;
2095 }
2096 }
2097
2098 aParamsSeq[4] = uno::makeAny( rtl::OUString::createFromAscii( "-zipdir" ) );
2099 rtl::OUString aSystemPath;
2100 osl::FileBase::getSystemPathFromFileURL( aZipDir, aSystemPath );
2101 aParamsSeq[5] = uno::makeAny( aSystemPath );
2102
2103 if( !bIsWriteAccess )
2104 {
2105 aParamsSeq[6] = uno::makeAny( rtl::OUString::createFromAscii( "-srcdir" ) );
2106 rtl::OUString aSrcDirVal;
2107 osl::FileBase::getSystemPathFromFileURL( aLangURL, aSrcDirVal );
2108 aParamsSeq[7] = uno::makeAny( aSrcDirVal );
2109 }
2110
2111 Sequence< sal_Int16 > aOutParamIndex;
2112 Sequence< uno::Any > aOutParam;
2113 uno::Any aRet = xInvocation->invoke( rtl::OUString::createFromAscii( "createIndex" ),
2114 aParamsSeq, aOutParamIndex, aOutParam );
2115
2116 if( bIsWriteAccess )
2117 aIndexFolder = implGetFileFromPackage( rtl::OUString::createFromAscii( ".idxl" ), xPackage );
2118 else
2119 aIndexFolder = aZipDir + rtl::OUString::createFromAscii( "/help.idxl" );
2120 }
2121 }
2122 catch (Exception &)
2123 {}
2124 }
2125 }
2126
2127 return aIndexFolder;
2128 }
2129
deleteTempIndexFolder(const rtl::OUString & aIndexFolder)2130 void IndexFolderIterator::deleteTempIndexFolder( const rtl::OUString& aIndexFolder )
2131 {
2132 sal_Int32 nLastSlash = aIndexFolder.lastIndexOf( '/' );
2133 if( nLastSlash != -1 )
2134 {
2135 rtl::OUString aTmpFolder = aIndexFolder.copy( 0, nLastSlash );
2136 try
2137 {
2138 m_xSFA->kill( aTmpFolder );
2139 }
2140 catch (Exception &)
2141 {}
2142 }
2143 }
2144