1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <rtl/character.hxx>
22 #include <rtl/ustrbuf.hxx>
23 #include <sal/log.hxx>
24 #include <o3tl/safeint.hxx>
25 #include <o3tl/string_view.hxx>
26 #include <osl/diagnose.h>
29 #include <osl/file.hxx>
30 #include <unotools/configmgr.hxx>
31 #include <com/sun/star/configuration/theDefaultProvider.hpp>
32 #include <com/sun/star/ucb/SimpleFileAccess.hpp>
34 #include <comphelper/processfactory.hxx>
35 #include <comphelper/propertysequence.hxx>
36 #include <com/sun/star/deployment/thePackageManagerFactory.hpp>
37 #include <com/sun/star/util/theMacroExpander.hpp>
38 #include <com/sun/star/uri/UriReferenceFactory.hpp>
39 #include <com/sun/star/uri/XVndSunStarExpandUrl.hpp>
40 #include <i18nlangtag/languagetag.hxx>
41 #include <unotools/pathoptions.hxx>
48 friend class TVChildTarget
;
53 explicit TVDom( TVDom
* arent
= nullptr )
54 : kind( Kind::other
),
62 children
.emplace_back( new TVDom( this ) );
63 return children
.back().get();
66 void newChild(std::unique_ptr
<TVDom
> p
)
68 children
.emplace_back(std::move(p
));
69 children
.back()->parent
= this;
72 TVDom
* getParent() const
77 return const_cast<TVDom
*>(this); // I am my own parent, if I am the root
86 bool isLeaf() const { return kind
== TVDom::Kind::tree_leaf
; }
87 void setKind( Kind ind
) { kind
= ind
; }
89 void setApplication( const char* appl
)
91 application
= OUString( appl
,
93 RTL_TEXTENCODING_UTF8
);
96 void setTitle( const char* itle
)
98 title
+= OUString( itle
,
100 RTL_TEXTENCODING_UTF8
);
103 void setTitle( const XML_Char
* itle
,int len
)
105 title
+= OUString( itle
,
107 RTL_TEXTENCODING_UTF8
);
110 void setId( const char* d
)
114 RTL_TEXTENCODING_UTF8
);
117 void setAnchor( const char* nchor
)
119 anchor
= OUString( nchor
,
121 RTL_TEXTENCODING_UTF8
);
124 OUString
const & getTargetURL()
126 if( targetURL
.isEmpty() )
128 targetURL
= "vnd.sun.star.help://" + id
;
137 OUString application
;
144 std::vector
< std::unique_ptr
<TVDom
> > children
;
149 using namespace treeview
;
150 using namespace com::sun::star
;
151 using namespace com::sun::star::uno
;
152 using namespace com::sun::star::beans
;
153 using namespace com::sun::star::configuration
;
154 using namespace com::sun::star::lang
;
155 using namespace com::sun::star::util
;
156 using namespace com::sun::star::container
;
157 using namespace com::sun::star::deployment
;
159 const char prodName
[] = "%PRODUCTNAME";
160 const char vendName
[] = "%VENDORNAME";
161 const char vendVersion
[] = "%VENDORVERSION";
162 const char vendShort
[] = "%VENDORSHORT";
163 const char prodVersion
[] = "%PRODUCTVERSION";
165 ConfigData::ConfigData()
169 void ConfigData::replaceName( OUString
& oustring
) const
171 sal_Int32 idx
= -1,k
= 0,off
;
173 OUStringBuffer
aStrBuf( 0 );
175 while( ( idx
= oustring
.indexOf( '%', ++idx
) ) != -1 )
177 if( oustring
.indexOf( prodName
,idx
) == idx
)
179 else if( oustring
.indexOf( prodVersion
,idx
) == idx
)
180 off
= PRODUCTVERSION
;
181 else if( oustring
.indexOf( vendName
,idx
) == idx
)
183 else if( oustring
.indexOf( vendVersion
,idx
) == idx
)
185 else if( oustring
.indexOf( vendShort
,idx
) == idx
)
195 aStrBuf
.ensureCapacity( 256 );
198 aStrBuf
.append( &oustring
.getStr()[k
],idx
- k
);
199 aStrBuf
.append( m_vReplacement
[off
] );
200 k
= idx
+ m_vAdd
[off
];
206 if( k
< oustring
.getLength() )
207 aStrBuf
.append( &oustring
.getStr()[k
],oustring
.getLength()-k
);
208 oustring
= aStrBuf
.makeStringAndClear();
214 TVRead::TVRead( const ConfigData
& configData
,TVDom
* tvDom
)
219 Title
= tvDom
->title
;
220 configData
.replaceName( Title
);
221 if( tvDom
->isLeaf() )
223 TargetURL
= tvDom
->getTargetURL() + configData
.appendix
;
224 if( !tvDom
->anchor
.isEmpty() )
225 TargetURL
+= "#" + tvDom
->anchor
;
228 Children
= new TVChildTarget( configData
,tvDom
);
238 TVRead::getByName( const OUString
& aName
)
242 if( aName
== "Title" )
244 else if( aName
== "TargetURL" )
246 else if( aName
== "Children" )
248 cppu::OWeakObject
* p
= Children
.get();
249 aAny
<<= Reference
< XInterface
>( p
);
257 throw NoSuchElementException();
260 Sequence
< OUString
> SAL_CALL
261 TVRead::getElementNames( )
263 return { "Title", "TargetURL", "Children" };
267 TVRead::hasByName( const OUString
& aName
)
269 if( aName
== "Title" ||
270 aName
== "TargetURL" ||
271 aName
== "Children" )
277 // XHierarchicalNameAccess
280 TVRead::getByHierarchicalName( const OUString
& aName
)
283 if( aName
.startsWith("Children/", &aRest
) )
284 return Children
->getByHierarchicalName( aRest
);
286 return getByName( aName
);
290 TVRead::hasByHierarchicalName( const OUString
& aName
)
293 if( aName
.startsWith("Children/", &aRest
) )
294 return Children
->hasByHierarchicalName( aRest
);
296 return hasByName( aName
);
299 /**************************************************************************/
303 /**************************************************************************/
307 static void start_handler(void *userData
,
308 const XML_Char
*name
,
309 const XML_Char
**atts
)
313 if( strcmp( name
,"help_section" ) == 0 ||
314 strcmp( name
,"node" ) == 0 )
315 kind
= TVDom::Kind::tree_node
;
316 else if( strcmp( name
,"topic" ) == 0 )
317 kind
= TVDom::Kind::tree_leaf
;
321 TVDom
**tvDom
= static_cast< TVDom
** >( userData
);
325 *tvDom
= p
->newChild();
331 if( strcmp( *atts
,"application" ) == 0 )
332 p
->setApplication( *(atts
+1) );
333 else if( strcmp( *atts
,"title" ) == 0 )
334 p
->setTitle( *(atts
+1) );
335 else if( strcmp( *atts
,"id" ) == 0 )
336 p
->setId( *(atts
+1) );
337 else if( strcmp( *atts
,"anchor" ) == 0 )
338 p
->setAnchor( *(atts
+1) );
344 static void end_handler(void *userData
,
345 SAL_UNUSED_PARAMETER
const XML_Char
* )
347 TVDom
**tvDom
= static_cast< TVDom
** >( userData
);
348 *tvDom
= (*tvDom
)->getParent();
351 static void data_handler( void *userData
,
355 TVDom
**tvDom
= static_cast< TVDom
** >( userData
);
356 if( (*tvDom
)->isLeaf() )
357 (*tvDom
)->setTitle( s
,len
);
362 TVChildTarget::TVChildTarget( const ConfigData
& configData
,TVDom
* tvDom
)
364 Elements
.resize( tvDom
->children
.size() );
365 for( size_t i
= 0; i
< Elements
.size(); ++i
)
366 Elements
[i
] = new TVRead( configData
,tvDom
->children
[i
].get() );
369 TVChildTarget::TVChildTarget( const Reference
< XComponentContext
>& xContext
)
371 ConfigData configData
= init( xContext
);
373 if( configData
.locale
.isEmpty() || configData
.system
.isEmpty() )
376 sal_uInt64 ret
,len
= 0;
377 int j
= configData
.vFileURL
.size();
380 TVDom
* pTVDom
= &tvDom
;
384 len
= configData
.vFileLen
[--j
];
385 std::unique_ptr
<char[]> s(new char[ int(len
) ]); // the buffer to hold the installed files
386 osl::File
aFile( configData
.vFileURL
[j
] );
387 (void)aFile
.open( osl_File_OpenFlag_Read
);
388 aFile
.read( s
.get(),len
,ret
);
391 XML_Parser parser
= XML_ParserCreate( nullptr );
392 XML_SetElementHandler( parser
,
395 XML_SetCharacterDataHandler( parser
,
397 XML_SetUserData( parser
,&pTVDom
); // does not return this
399 XML_Status
const parsed
= XML_Parse(parser
, s
.get(), int(len
), j
==0);
400 SAL_WARN_IF(XML_STATUS_ERROR
== parsed
, "xmlhelp",
401 "TVChildTarget::TVChildTarget(): Tree file parsing failed");
403 XML_ParserFree( parser
);
407 // now TVDom holds the relevant information
409 Elements
.resize( tvDom
.children
.size() );
410 for( size_t i
= 0; i
< Elements
.size(); ++i
)
411 Elements
[i
] = new TVRead( configData
,tvDom
.children
[i
].get() );
414 TVChildTarget::~TVChildTarget()
418 void TVChildTarget::Check(TVDom
* tvDom
)
420 if (tvDom
->children
.empty())
428 while((i
<tvDom
->children
.size()-1) && (!h
))
430 if (((tvDom
->children
[i
])->application
== (tvDom
->children
[tvDom
->children
.size()-1])->application
) &&
431 ((tvDom
->children
[i
])->id
== (tvDom
->children
[tvDom
->children
.size()-1])->id
))
433 TVDom
* p
= tvDom
->children
.back().get();
435 for(auto & k
: p
->children
)
437 std::unique_ptr
<TVDom
> tmp(SearchAndInsert(std::move(k
), tvDom
->children
[i
].get()));
440 tvDom
->children
[i
]->newChild(std::move(tmp
));
444 tvDom
->children
.pop_back();
451 std::unique_ptr
<TVDom
>
452 TVChildTarget::SearchAndInsert(std::unique_ptr
<TVDom
> p
, TVDom
* tvDom
)
454 if (p
->isLeaf()) return p
;
459 std::vector
< std::unique_ptr
<TVDom
> >::iterator max_It
, i
;
460 max_It
= tvDom
->children
.begin();
463 sal_Int32 p_int
= p
->id
.toInt32();
465 for(i
= tvDom
->children
.begin(); i
!=tvDom
->children
.end(); ++i
)
466 if (!((*i
)->isLeaf()) &&
467 ((*i
)->id
.getLength() == p
->id
.getLength()) &&
468 (p
->id
.replaceAt((*i
)->parent
->id
.getLength(), p
->id
.getLength()-(*i
)->parent
->id
.getLength(), u
"") == (*i
)->parent
->id
)) //prefix check
471 c_int
= (*i
)->id
.toInt32();
475 (*(tvDom
->children
.insert(i
+1, std::move(p
))))->parent
= tvDom
;
478 else if(c_int
>max
&& c_int
< p_int
)
486 (*(tvDom
->children
.insert(max_It
, std::move(p
))))->parent
= tvDom
;
491 for (auto& child
: tvDom
->children
)
493 p
= SearchAndInsert(std::move(p
), child
.get());
502 TVChildTarget::getByName( const OUString
& aName
)
504 std::u16string_view
num( aName
.subView( 2, aName
.getLength()-4 ) );
505 sal_Int32 idx
= o3tl::toInt32(num
) - 1;
506 if( idx
< 0 || Elements
.size() <= o3tl::make_unsigned( idx
) )
507 throw NoSuchElementException();
509 cppu::OWeakObject
* p
= Elements
[idx
].get();
510 return Any( Reference
< XInterface
>( p
) );
513 Sequence
< OUString
> SAL_CALL
514 TVChildTarget::getElementNames( )
516 Sequence
< OUString
> seq( Elements
.size() );
517 auto seqRange
= asNonConstRange(seq
);
518 for( size_t i
= 0; i
< Elements
.size(); ++i
)
519 seqRange
[i
] = OUString::number( 1+i
);
525 TVChildTarget::hasByName( const OUString
& aName
)
527 std::u16string_view
num( aName
.subView( 2, aName
.getLength()-4 ) );
528 sal_Int32 idx
= o3tl::toInt32(num
) - 1;
529 if( idx
< 0 || Elements
.size() <= o3tl::make_unsigned( idx
) )
535 // XHierarchicalNameAccess
538 TVChildTarget::getByHierarchicalName( const OUString
& aName
)
542 if( ( idx
= aName
.indexOf( '/' ) ) != -1 )
544 std::u16string_view
num( aName
.subView( 2, idx
-4 ) );
545 sal_Int32 pref
= o3tl::toInt32(num
) - 1;
547 if( pref
< 0 || Elements
.size() <= o3tl::make_unsigned( pref
) )
548 throw NoSuchElementException();
550 return Elements
[pref
]->getByHierarchicalName( aName
.copy( 1 + idx
) );
553 return getByName( aName
);
557 TVChildTarget::hasByHierarchicalName( const OUString
& aName
)
561 if( ( idx
= aName
.indexOf( '/' ) ) != -1 )
563 std::u16string_view
num( aName
.subView( 2, idx
-4 ) );
564 sal_Int32 pref
= o3tl::toInt32(num
) - 1;
565 if( pref
< 0 || Elements
.size() <= o3tl::make_unsigned( pref
) )
568 return Elements
[pref
]->hasByHierarchicalName( aName
.copy( 1 + idx
) );
571 return hasByName( aName
);
574 ConfigData
TVChildTarget::init( const Reference
< XComponentContext
>& xContext
)
576 ConfigData configData
;
577 Reference
< XMultiServiceFactory
> sProvider( getConfiguration(xContext
) );
579 /**********************************************************************/
580 /* reading Office.Common */
581 /**********************************************************************/
583 Reference
< XHierarchicalNameAccess
> xHierAccess( getHierAccess( sProvider
,
584 "org.openoffice.Office.Common" ) );
585 OUString
system( getKey( xHierAccess
,"Help/System" ) );
586 bool showBasic( getBooleanKey(xHierAccess
,"Help/ShowBasic") );
587 OUString
instPath( getKey( xHierAccess
,"Path/Current/Help" ) );
588 if( instPath
.isEmpty() )
589 // try to determine path from default
590 instPath
= "$(instpath)/help";
592 // replace anything like $(instpath);
595 /**********************************************************************/
597 /**********************************************************************/
599 xHierAccess
= getHierAccess( sProvider
,
600 "org.openoffice.Setup" );
602 OUString
setupversion( getKey( xHierAccess
,"Product/ooSetupVersion" ) );
603 OUString setupextension
;
607 Reference
< lang::XMultiServiceFactory
> xConfigProvider
= theDefaultProvider::get( xContext
);
609 uno::Sequence
<uno::Any
> lParams(comphelper::InitAnyPropertySequence(
611 {"nodepath", uno::Any(OUString("/org.openoffice.Setup/Product"))}
615 uno::Reference
< uno::XInterface
> xCFG( xConfigProvider
->createInstanceWithArguments(
616 "com.sun.star.configuration.ConfigurationAccess",
619 uno::Reference
< container::XNameAccess
> xDirectAccess(xCFG
, uno::UNO_QUERY
);
620 uno::Any aRet
= xDirectAccess
->getByName("ooSetupExtension");
622 aRet
>>= setupextension
;
624 catch ( uno::Exception
& )
628 OUString
productVersion( setupversion
+ " " + setupextension
);
629 OUString
locale( getKey( xHierAccess
,"L10N/ooLocale" ) );
631 // Determine fileurl from url and locale
633 osl::FileBase::RC errFile
= osl::FileBase::getFileURLFromSystemPath( instPath
,url
);
634 if( errFile
!= osl::FileBase::E_None
) return configData
;
635 if( !url
.endsWith("/") )
639 osl::DirectoryItem aDirItem
;
640 if( osl::FileBase::E_None
== osl::DirectoryItem::get( url
+ locale
,aDirItem
) )
642 else if( ( ( idx
= locale
.indexOf( '-' ) ) != -1 ||
643 ( idx
= locale
.indexOf( '_' ) ) != -1 ) &&
644 osl::FileBase::E_None
== osl::DirectoryItem::get( url
+ locale
.subView( 0,idx
),
646 ret
= locale
.copy( 0,idx
);
654 // first of all, try do determine whether there are any *.tree files present
656 // Start with extensions to set them at the end of the list
657 TreeFileIterator
aTreeIt( locale
);
662 aTreeFile
= aTreeIt
.nextTreeFile( nFileSize
);
663 if( aTreeFile
.isEmpty() )
665 configData
.vFileLen
.push_back( nFileSize
);
666 configData
.vFileURL
.push_back( aTreeFile
);
669 osl::Directory
aDirectory( url
);
670 osl::FileStatus
aFileStatus(
671 osl_FileStatus_Mask_FileName
| osl_FileStatus_Mask_FileURL
);
672 if( osl::Directory::E_None
== aDirectory
.open() )
674 OUString aFileUrl
, aFileName
;
675 while( aDirectory
.getNextItem( aDirItem
) == osl::FileBase::E_None
&&
676 aDirItem
.getFileStatus( aFileStatus
) == osl::FileBase::E_None
&&
677 aFileStatus
.isValid( osl_FileStatus_Mask_FileURL
) &&
678 aFileStatus
.isValid( osl_FileStatus_Mask_FileName
) )
680 aFileUrl
= aFileStatus
.getFileURL();
681 aFileName
= aFileStatus
.getFileName();
682 int idx_
= aFileName
.lastIndexOf( '.' );
686 const sal_Unicode
* str
= aFileName
.getStr();
688 if( aFileName
.getLength() == idx_
+ 5 &&
689 ( str
[idx_
+ 1] == 't' || str
[idx_
+ 1] == 'T' ) &&
690 ( str
[idx_
+ 2] == 'r' || str
[idx_
+ 2] == 'R' ) &&
691 ( str
[idx_
+ 3] == 'e' || str
[idx_
+ 3] == 'E' ) &&
692 ( str
[idx_
+ 4] == 'e' || str
[idx_
+ 4] == 'E' ) )
694 OUString baseName
= aFileName
.copy(0,idx_
).toAsciiLowerCase();
695 if(! showBasic
&& baseName
== "sbasic" )
697 osl::File
aFile( aFileUrl
);
698 if( osl::FileBase::E_None
== aFile
.open( osl_File_OpenFlag_Read
) )
700 // use the file size, not aFileStatus size, in case the
701 // tree file is a symlink
703 aFile
.getSize( nSize
);
704 configData
.vFileLen
.push_back( nSize
);
705 configData
.vFileURL
.push_back( aFileUrl
);
713 configData
.m_vAdd
[0] = 12;
714 configData
.m_vAdd
[1] = 15;
715 configData
.m_vAdd
[2] = 11;
716 configData
.m_vAdd
[3] = 14;
717 configData
.m_vAdd
[4] = 12;
718 configData
.m_vReplacement
[0] = utl::ConfigManager::getProductName();
719 configData
.m_vReplacement
[1] = productVersion
;
720 // m_vReplacement[2...4] (vendorName/-Version/-Short) are empty strings
722 configData
.system
= system
;
723 configData
.locale
= locale
;
724 configData
.appendix
=
734 Reference
< XMultiServiceFactory
>
735 TVChildTarget::getConfiguration(const Reference
< XComponentContext
>& rxContext
)
737 Reference
< XMultiServiceFactory
> xProvider
;
742 xProvider
= theDefaultProvider::get( rxContext
);
744 catch( const css::uno::Exception
& )
746 OSL_ENSURE( xProvider
.is(),"can not instantiate configuration" );
753 Reference
< XHierarchicalNameAccess
>
754 TVChildTarget::getHierAccess( const Reference
< XMultiServiceFactory
>& sProvider
,
757 Reference
< XHierarchicalNameAccess
> xHierAccess
;
764 Reference
< XHierarchicalNameAccess
>
765 ( sProvider
->createInstanceWithArguments( "com.sun.star.configuration.ConfigurationAccess", { Any(OUString::createFromAscii(file
)) }),
768 catch( const css::uno::Exception
& )
777 TVChildTarget::getKey( const Reference
< XHierarchicalNameAccess
>& xHierAccess
,
781 if( xHierAccess
.is() )
787 xHierAccess
->getByHierarchicalName( OUString::createFromAscii( key
) );
789 catch( const css::container::NoSuchElementException
& )
798 TVChildTarget::getBooleanKey(const Reference
<
799 XHierarchicalNameAccess
>& xHierAccess
,
803 if( xHierAccess
.is() )
809 xHierAccess
->getByHierarchicalName(
810 OUString::createFromAscii(key
));
812 catch( const css::container::NoSuchElementException
& )
820 void TVChildTarget::subst( OUString
& instpath
)
822 SvtPathOptions aOptions
;
823 instpath
= aOptions
.SubstituteVariable( instpath
);
827 const char aHelpMediaType
[] = "application/vnd.sun.star.help";
829 TreeFileIterator::TreeFileIterator( const OUString
& aLanguage
)
830 : m_eState( IteratorState::UserExtensions
)
831 , m_aLanguage( aLanguage
)
833 m_xContext
= ::comphelper::getProcessComponentContext();
834 if( !m_xContext
.is() )
836 throw RuntimeException( "TreeFileIterator::TreeFileIterator(), no XComponentContext" );
839 m_xSFA
= ucb::SimpleFileAccess::create(m_xContext
);
841 m_bUserPackagesLoaded
= false;
842 m_bSharedPackagesLoaded
= false;
843 m_bBundledPackagesLoaded
= false;
845 m_iSharedPackage
= 0;
846 m_iBundledPackage
= 0;
849 Reference
< deployment::XPackage
> TreeFileIterator::implGetHelpPackageFromPackage
850 ( const Reference
< deployment::XPackage
>& xPackage
, Reference
< deployment::XPackage
>& o_xParentPackageBundle
)
852 o_xParentPackageBundle
.clear();
854 Reference
< deployment::XPackage
> xHelpPackage
;
858 // Check if parent package is registered
859 beans::Optional
< beans::Ambiguous
<sal_Bool
> > option( xPackage
->isRegistered
860 ( Reference
<task::XAbortChannel
>(), Reference
<ucb::XCommandEnvironment
>() ) );
861 bool bRegistered
= false;
862 if( option
.IsPresent
)
864 beans::Ambiguous
<sal_Bool
> const & reg
= option
.Value
;
865 if( !reg
.IsAmbiguous
&& reg
.Value
)
871 if( xPackage
->isBundle() )
873 const Sequence
< Reference
< deployment::XPackage
> > aPkgSeq
= xPackage
->getBundle
874 ( Reference
<task::XAbortChannel
>(), Reference
<ucb::XCommandEnvironment
>() );
875 auto pSubPkg
= std::find_if(aPkgSeq
.begin(), aPkgSeq
.end(),
876 [](const Reference
< deployment::XPackage
>& xSubPkg
) {
877 const Reference
< deployment::XPackageTypeInfo
> xPackageTypeInfo
= xSubPkg
->getPackageType();
878 OUString aMediaType
= xPackageTypeInfo
->getMediaType();
879 return aMediaType
== aHelpMediaType
;
881 if (pSubPkg
!= aPkgSeq
.end())
883 xHelpPackage
= *pSubPkg
;
884 o_xParentPackageBundle
= xPackage
;
889 const Reference
< deployment::XPackageTypeInfo
> xPackageTypeInfo
= xPackage
->getPackageType();
890 OUString aMediaType
= xPackageTypeInfo
->getMediaType();
891 if( aMediaType
== aHelpMediaType
)
892 xHelpPackage
= xPackage
;
898 Reference
< deployment::XPackage
> TreeFileIterator::implGetNextUserHelpPackage
899 ( Reference
< deployment::XPackage
>& o_xParentPackageBundle
)
901 Reference
< deployment::XPackage
> xHelpPackage
;
903 if( !m_bUserPackagesLoaded
)
905 Reference
< XPackageManager
> xUserManager
=
906 thePackageManagerFactory::get( m_xContext
)->getPackageManager("user");
907 m_aUserPackagesSeq
= xUserManager
->getDeployedPackages
908 ( Reference
< task::XAbortChannel
>(), Reference
< ucb::XCommandEnvironment
>() );
910 m_bUserPackagesLoaded
= true;
913 if( m_iUserPackage
== m_aUserPackagesSeq
.getLength() )
915 m_eState
= IteratorState::SharedExtensions
; // Later: SHARED_MODULE
919 const Reference
< deployment::XPackage
>* pUserPackages
= m_aUserPackagesSeq
.getConstArray();
920 Reference
< deployment::XPackage
> xPackage
= pUserPackages
[ m_iUserPackage
++ ];
921 OSL_ENSURE( xPackage
.is(), "TreeFileIterator::implGetNextUserHelpPackage(): Invalid package" );
922 xHelpPackage
= implGetHelpPackageFromPackage( xPackage
, o_xParentPackageBundle
);
928 Reference
< deployment::XPackage
> TreeFileIterator::implGetNextSharedHelpPackage
929 ( Reference
< deployment::XPackage
>& o_xParentPackageBundle
)
931 Reference
< deployment::XPackage
> xHelpPackage
;
933 if( !m_bSharedPackagesLoaded
)
935 Reference
< XPackageManager
> xSharedManager
=
936 thePackageManagerFactory::get( m_xContext
)->getPackageManager("shared");
937 m_aSharedPackagesSeq
= xSharedManager
->getDeployedPackages
938 ( Reference
< task::XAbortChannel
>(), Reference
< ucb::XCommandEnvironment
>() );
940 m_bSharedPackagesLoaded
= true;
943 if( m_iSharedPackage
== m_aSharedPackagesSeq
.getLength() )
945 m_eState
= IteratorState::BundledExtensions
;
949 const Reference
< deployment::XPackage
>* pSharedPackages
= m_aSharedPackagesSeq
.getConstArray();
950 Reference
< deployment::XPackage
> xPackage
= pSharedPackages
[ m_iSharedPackage
++ ];
951 OSL_ENSURE( xPackage
.is(), "TreeFileIterator::implGetNextSharedHelpPackage(): Invalid package" );
952 xHelpPackage
= implGetHelpPackageFromPackage( xPackage
, o_xParentPackageBundle
);
958 Reference
< deployment::XPackage
> TreeFileIterator::implGetNextBundledHelpPackage
959 ( Reference
< deployment::XPackage
>& o_xParentPackageBundle
)
961 Reference
< deployment::XPackage
> xHelpPackage
;
963 if( !m_bBundledPackagesLoaded
)
965 Reference
< XPackageManager
> xBundledManager
=
966 thePackageManagerFactory::get( m_xContext
)->getPackageManager("bundled");
967 m_aBundledPackagesSeq
= xBundledManager
->getDeployedPackages
968 ( Reference
< task::XAbortChannel
>(), Reference
< ucb::XCommandEnvironment
>() );
970 m_bBundledPackagesLoaded
= true;
973 if( m_iBundledPackage
== m_aBundledPackagesSeq
.getLength() )
975 m_eState
= IteratorState::EndReached
;
979 const Reference
< deployment::XPackage
>* pBundledPackages
= m_aBundledPackagesSeq
.getConstArray();
980 Reference
< deployment::XPackage
> xPackage
= pBundledPackages
[ m_iBundledPackage
++ ];
981 OSL_ENSURE( xPackage
.is(), "TreeFileIterator::implGetNextBundledHelpPackage(): Invalid package" );
982 xHelpPackage
= implGetHelpPackageFromPackage( xPackage
, o_xParentPackageBundle
);
988 static bool isLetter( sal_Unicode c
)
990 return rtl::isAsciiAlpha(c
);
993 void TreeFileIterator::implGetLanguageVectorFromPackage( ::std::vector
< OUString
> &rv
,
994 const css::uno::Reference
< css::deployment::XPackage
>& xPackage
)
997 OUString aExtensionPath
= xPackage
->getURL();
998 const Sequence
< OUString
> aEntrySeq
= m_xSFA
->getFolderContents( aExtensionPath
, true );
1000 for( const OUString
& aEntry
: aEntrySeq
)
1002 if( m_xSFA
->isFolder( aEntry
) )
1004 sal_Int32 nLastSlash
= aEntry
.lastIndexOf( '/' );
1005 if( nLastSlash
!= -1 )
1007 OUString aPureEntry
= aEntry
.copy( nLastSlash
+ 1 );
1009 // Check language scheme
1010 int nLen
= aPureEntry
.getLength();
1011 const sal_Unicode
* pc
= aPureEntry
.getStr();
1012 bool bStartCanBeLanguage
= ( nLen
>= 2 && isLetter( pc
[0] ) && isLetter( pc
[1] ) );
1013 bool bIsLanguage
= bStartCanBeLanguage
&&
1014 ( nLen
== 2 || (nLen
== 5 && pc
[2] == '-' && isLetter( pc
[3] ) && isLetter( pc
[4] )) );
1016 rv
.push_back( aPureEntry
);
1023 OUString
TreeFileIterator::nextTreeFile( sal_Int32
& rnFileSize
)
1027 while( aRetFile
.isEmpty() && m_eState
!= IteratorState::EndReached
)
1031 case IteratorState::UserExtensions
:
1033 Reference
< deployment::XPackage
> xParentPackageBundle
;
1034 Reference
< deployment::XPackage
> xHelpPackage
= implGetNextUserHelpPackage( xParentPackageBundle
);
1035 if( !xHelpPackage
.is() )
1038 aRetFile
= implGetTreeFileFromPackage( rnFileSize
, xHelpPackage
);
1042 case IteratorState::SharedExtensions
:
1044 Reference
< deployment::XPackage
> xParentPackageBundle
;
1045 Reference
< deployment::XPackage
> xHelpPackage
= implGetNextSharedHelpPackage( xParentPackageBundle
);
1046 if( !xHelpPackage
.is() )
1049 aRetFile
= implGetTreeFileFromPackage( rnFileSize
, xHelpPackage
);
1052 case IteratorState::BundledExtensions
:
1054 Reference
< deployment::XPackage
> xParentPackageBundle
;
1055 Reference
< deployment::XPackage
> xHelpPackage
= implGetNextBundledHelpPackage( xParentPackageBundle
);
1056 if( !xHelpPackage
.is() )
1059 aRetFile
= implGetTreeFileFromPackage( rnFileSize
, xHelpPackage
);
1063 case IteratorState::EndReached
:
1064 OSL_FAIL( "DataBaseIterator::nextTreeFile(): Invalid case IteratorState::EndReached" );
1072 OUString
TreeFileIterator::expandURL( const OUString
& aURL
)
1074 static Reference
< util::XMacroExpander
> xMacroExpander
;
1075 static Reference
< uri::XUriReferenceFactory
> xFac
;
1077 std::scoped_lock
aGuard( m_aMutex
);
1079 if( !xMacroExpander
.is() || !xFac
.is() )
1081 xFac
= uri::UriReferenceFactory::create( m_xContext
);
1083 xMacroExpander
= util::theMacroExpander::get(m_xContext
);
1086 OUString aRetURL
= aURL
;
1087 Reference
< uri::XUriReference
> uriRef
;
1090 uriRef
= xFac
->parse( aRetURL
);
1093 Reference
< uri::XVndSunStarExpandUrl
> sxUri( uriRef
, UNO_QUERY
);
1097 aRetURL
= sxUri
->expand( xMacroExpander
);
1103 OUString
TreeFileIterator::implGetTreeFileFromPackage
1104 ( sal_Int32
& rnFileSize
, const Reference
< deployment::XPackage
>& xPackage
)
1107 OUString aLanguage
= m_aLanguage
;
1108 for( sal_Int32 iPass
= 0 ; iPass
< 2 ; ++iPass
)
1110 aRetFile
= expandURL( xPackage
->getURL() + "/" + aLanguage
+ "/help.tree" );
1113 if( m_xSFA
->exists( aRetFile
) )
1116 ::std::vector
< OUString
> av
;
1117 implGetLanguageVectorFromPackage( av
, xPackage
);
1118 ::std::vector
< OUString
>::const_iterator pFound
= LanguageTag::getFallback( av
, m_aLanguage
);
1119 if( pFound
!= av
.end() )
1120 aLanguage
= *pFound
;
1125 if( m_xSFA
->exists( aRetFile
) )
1126 rnFileSize
= m_xSFA
->getSize( aRetFile
);
1133 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */