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