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>
49 friend class TVChildTarget
;
54 explicit TVDom( TVDom
* arent
= nullptr )
55 : kind( Kind::other
),
63 children
.emplace_back( new TVDom( this ) );
64 return children
.back().get();
67 void newChild(std::unique_ptr
<TVDom
> p
)
69 children
.emplace_back(std::move(p
));
70 children
.back()->parent
= this;
73 TVDom
* getParent() const
78 return const_cast<TVDom
*>(this); // I am my own parent, if I am the root
87 bool isLeaf() const { return kind
== TVDom::Kind::tree_leaf
; }
88 void setKind( Kind ind
) { kind
= ind
; }
90 void setApplication( const char* appl
)
92 application
= OUString( appl
,
94 RTL_TEXTENCODING_UTF8
);
97 void setTitle( const char* itle
)
99 title
+= OUString( itle
,
101 RTL_TEXTENCODING_UTF8
);
104 void setTitle( const XML_Char
* itle
,int len
)
106 title
+= OUString( itle
,
108 RTL_TEXTENCODING_UTF8
);
111 void setId( const char* d
)
115 RTL_TEXTENCODING_UTF8
);
118 void setAnchor( const char* nchor
)
120 anchor
= OUString( nchor
,
122 RTL_TEXTENCODING_UTF8
);
125 OUString
const & getTargetURL()
127 if( targetURL
.isEmpty() )
129 targetURL
= "vnd.sun.star.help://" + id
;
138 OUString application
;
145 std::vector
< std::unique_ptr
<TVDom
> > children
;
150 using namespace treeview
;
151 using namespace com::sun::star
;
152 using namespace com::sun::star::uno
;
153 using namespace com::sun::star::beans
;
154 using namespace com::sun::star::configuration
;
155 using namespace com::sun::star::lang
;
156 using namespace com::sun::star::util
;
157 using namespace com::sun::star::container
;
158 using namespace com::sun::star::deployment
;
160 const char prodName
[] = "%PRODUCTNAME";
161 const char vendName
[] = "%VENDORNAME";
162 const char vendVersion
[] = "%VENDORVERSION";
163 const char vendShort
[] = "%VENDORSHORT";
164 const char prodVersion
[] = "%PRODUCTVERSION";
166 ConfigData::ConfigData()
170 void ConfigData::replaceName( OUString
& oustring
) const
172 sal_Int32 idx
= -1,k
= 0,off
;
174 OUStringBuffer
aStrBuf( 0 );
176 while( ( idx
= oustring
.indexOf( '%', ++idx
) ) != -1 )
178 if( oustring
.indexOf( prodName
,idx
) == idx
)
180 else if( oustring
.indexOf( prodVersion
,idx
) == idx
)
181 off
= PRODUCTVERSION
;
182 else if( oustring
.indexOf( vendName
,idx
) == idx
)
184 else if( oustring
.indexOf( vendVersion
,idx
) == idx
)
186 else if( oustring
.indexOf( vendShort
,idx
) == idx
)
196 aStrBuf
.ensureCapacity( 256 );
199 aStrBuf
.append( &oustring
.getStr()[k
],idx
- k
);
200 aStrBuf
.append( m_vReplacement
[off
] );
201 k
= idx
+ m_vAdd
[off
];
207 if( k
< oustring
.getLength() )
208 aStrBuf
.append( &oustring
.getStr()[k
],oustring
.getLength()-k
);
209 oustring
= aStrBuf
.makeStringAndClear();
215 TVRead::TVRead( const ConfigData
& configData
,TVDom
* tvDom
)
220 Title
= tvDom
->title
;
221 configData
.replaceName( Title
);
222 if( tvDom
->isLeaf() )
224 TargetURL
= tvDom
->getTargetURL() + configData
.appendix
;
225 if( !tvDom
->anchor
.isEmpty() )
226 TargetURL
+= "#" + tvDom
->anchor
;
229 Children
= new TVChildTarget( configData
,tvDom
);
239 TVRead::getByName( const OUString
& aName
)
243 if( aName
== "Title" )
245 else if( aName
== "TargetURL" )
247 else if( aName
== "Children" )
249 cppu::OWeakObject
* p
= Children
.get();
250 aAny
<<= Reference
< XInterface
>( p
);
258 throw NoSuchElementException();
261 Sequence
< OUString
> SAL_CALL
262 TVRead::getElementNames( )
264 return { "Title", "TargetURL", "Children" };
268 TVRead::hasByName( const OUString
& aName
)
270 if( aName
== "Title" ||
271 aName
== "TargetURL" ||
272 aName
== "Children" )
278 // XHierarchicalNameAccess
281 TVRead::getByHierarchicalName( const OUString
& aName
)
284 if( aName
.startsWith("Children/", &aRest
) )
285 return Children
->getByHierarchicalName( aRest
);
287 return getByName( aName
);
291 TVRead::hasByHierarchicalName( const OUString
& aName
)
294 if( aName
.startsWith("Children/", &aRest
) )
295 return Children
->hasByHierarchicalName( aRest
);
297 return hasByName( aName
);
300 /**************************************************************************/
304 /**************************************************************************/
308 static void start_handler(void *userData
,
309 const XML_Char
*name
,
310 const XML_Char
**atts
)
314 if( strcmp( name
,"help_section" ) == 0 ||
315 strcmp( name
,"node" ) == 0 )
316 kind
= TVDom::Kind::tree_node
;
317 else if( strcmp( name
,"topic" ) == 0 )
318 kind
= TVDom::Kind::tree_leaf
;
322 TVDom
**tvDom
= static_cast< TVDom
** >( userData
);
326 *tvDom
= p
->newChild();
332 if( strcmp( *atts
,"application" ) == 0 )
333 p
->setApplication( *(atts
+1) );
334 else if( strcmp( *atts
,"title" ) == 0 )
335 p
->setTitle( *(atts
+1) );
336 else if( strcmp( *atts
,"id" ) == 0 )
337 p
->setId( *(atts
+1) );
338 else if( strcmp( *atts
,"anchor" ) == 0 )
339 p
->setAnchor( *(atts
+1) );
345 static void end_handler(void *userData
,
346 SAL_UNUSED_PARAMETER
const XML_Char
* )
348 TVDom
**tvDom
= static_cast< TVDom
** >( userData
);
349 *tvDom
= (*tvDom
)->getParent();
352 static void data_handler( void *userData
,
356 TVDom
**tvDom
= static_cast< TVDom
** >( userData
);
357 if( (*tvDom
)->isLeaf() )
358 (*tvDom
)->setTitle( s
,len
);
363 TVChildTarget::TVChildTarget( const ConfigData
& configData
,TVDom
* tvDom
)
365 Elements
.resize( tvDom
->children
.size() );
366 for( size_t i
= 0; i
< Elements
.size(); ++i
)
367 Elements
[i
] = new TVRead( configData
,tvDom
->children
[i
].get() );
370 TVChildTarget::TVChildTarget( const Reference
< XComponentContext
>& xContext
)
372 ConfigData configData
= init( xContext
);
374 if( configData
.locale
.isEmpty() || configData
.system
.isEmpty() )
377 sal_uInt64 ret
,len
= 0;
378 int j
= configData
.vFileURL
.size();
381 TVDom
* pTVDom
= &tvDom
;
385 len
= configData
.vFileLen
[--j
];
386 std::unique_ptr
<char[]> s(new char[ int(len
) ]); // the buffer to hold the installed files
387 osl::File
aFile( configData
.vFileURL
[j
] );
388 (void)aFile
.open( osl_File_OpenFlag_Read
);
389 aFile
.read( s
.get(),len
,ret
);
392 XML_Parser parser
= XML_ParserCreate( nullptr );
393 XML_SetElementHandler( parser
,
396 XML_SetCharacterDataHandler( parser
,
398 XML_SetUserData( parser
,&pTVDom
); // does not return this
400 XML_Status
const parsed
= XML_Parse(parser
, s
.get(), int(len
), j
==0);
401 SAL_WARN_IF(XML_STATUS_ERROR
== parsed
, "xmlhelp",
402 "TVChildTarget::TVChildTarget(): Tree file parsing failed");
404 XML_ParserFree( parser
);
408 // now TVDom holds the relevant information
410 Elements
.resize( tvDom
.children
.size() );
411 for( size_t i
= 0; i
< Elements
.size(); ++i
)
412 Elements
[i
] = new TVRead( configData
,tvDom
.children
[i
].get() );
415 TVChildTarget::~TVChildTarget()
419 void TVChildTarget::Check(TVDom
* tvDom
)
421 if (tvDom
->children
.empty())
429 while((i
<tvDom
->children
.size()-1) && (!h
))
431 if (((tvDom
->children
[i
])->application
== (tvDom
->children
[tvDom
->children
.size()-1])->application
) &&
432 ((tvDom
->children
[i
])->id
== (tvDom
->children
[tvDom
->children
.size()-1])->id
))
434 TVDom
* p
= tvDom
->children
.back().get();
436 for(auto & k
: p
->children
)
438 std::unique_ptr
<TVDom
> tmp(SearchAndInsert(std::move(k
), tvDom
->children
[i
].get()));
441 tvDom
->children
[i
]->newChild(std::move(tmp
));
445 tvDom
->children
.pop_back();
452 std::unique_ptr
<TVDom
>
453 TVChildTarget::SearchAndInsert(std::unique_ptr
<TVDom
> p
, TVDom
* tvDom
)
455 if (p
->isLeaf()) return p
;
460 std::vector
< std::unique_ptr
<TVDom
> >::iterator max_It
, i
;
461 max_It
= tvDom
->children
.begin();
464 sal_Int32 p_int
= p
->id
.toInt32();
466 for(i
= tvDom
->children
.begin(); i
!=tvDom
->children
.end(); ++i
)
467 if (!((*i
)->isLeaf()) &&
468 ((*i
)->id
.getLength() == p
->id
.getLength()) &&
469 (p
->id
.replaceAt((*i
)->parent
->id
.getLength(), p
->id
.getLength()-(*i
)->parent
->id
.getLength(), u
"") == (*i
)->parent
->id
)) //prefix check
472 c_int
= (*i
)->id
.toInt32();
476 (*(tvDom
->children
.insert(i
+1, std::move(p
))))->parent
= tvDom
;
479 else if(c_int
>max
&& c_int
< p_int
)
487 (*(tvDom
->children
.insert(max_It
, std::move(p
))))->parent
= tvDom
;
492 for (auto& child
: tvDom
->children
)
494 p
= SearchAndInsert(std::move(p
), child
.get());
503 TVChildTarget::getByName( const OUString
& aName
)
505 std::u16string_view
num( aName
.subView( 2, aName
.getLength()-4 ) );
506 sal_Int32 idx
= o3tl::toInt32(num
) - 1;
507 if( idx
< 0 || Elements
.size() <= o3tl::make_unsigned( idx
) )
508 throw NoSuchElementException();
510 cppu::OWeakObject
* p
= Elements
[idx
].get();
511 return Any( Reference
< XInterface
>( p
) );
514 Sequence
< OUString
> SAL_CALL
515 TVChildTarget::getElementNames( )
517 Sequence
< OUString
> seq( Elements
.size() );
518 auto seqRange
= asNonConstRange(seq
);
519 for( size_t i
= 0; i
< Elements
.size(); ++i
)
520 seqRange
[i
] = OUString::number( 1+i
);
526 TVChildTarget::hasByName( const OUString
& aName
)
528 std::u16string_view
num( aName
.subView( 2, aName
.getLength()-4 ) );
529 sal_Int32 idx
= o3tl::toInt32(num
) - 1;
530 if( idx
< 0 || Elements
.size() <= o3tl::make_unsigned( idx
) )
536 // XHierarchicalNameAccess
539 TVChildTarget::getByHierarchicalName( const OUString
& aName
)
543 if( ( idx
= aName
.indexOf( '/' ) ) != -1 )
545 std::u16string_view
num( aName
.subView( 2, idx
-4 ) );
546 sal_Int32 pref
= o3tl::toInt32(num
) - 1;
548 if( pref
< 0 || Elements
.size() <= o3tl::make_unsigned( pref
) )
549 throw NoSuchElementException();
551 return Elements
[pref
]->getByHierarchicalName( aName
.copy( 1 + idx
) );
554 return getByName( aName
);
558 TVChildTarget::hasByHierarchicalName( const OUString
& aName
)
562 if( ( idx
= aName
.indexOf( '/' ) ) != -1 )
564 std::u16string_view
num( aName
.subView( 2, idx
-4 ) );
565 sal_Int32 pref
= o3tl::toInt32(num
) - 1;
566 if( pref
< 0 || Elements
.size() <= o3tl::make_unsigned( pref
) )
569 return Elements
[pref
]->hasByHierarchicalName( aName
.copy( 1 + idx
) );
572 return hasByName( aName
);
575 ConfigData
TVChildTarget::init( const Reference
< XComponentContext
>& xContext
)
577 ConfigData configData
;
578 Reference
< XMultiServiceFactory
> sProvider( getConfiguration(xContext
) );
580 /**********************************************************************/
581 /* reading Office.Common */
582 /**********************************************************************/
584 Reference
< XHierarchicalNameAccess
> xHierAccess( getHierAccess( sProvider
,
585 "org.openoffice.Office.Common" ) );
586 OUString
system( getKey( xHierAccess
,"Help/System" ) );
587 bool showBasic( getBooleanKey(xHierAccess
,"Help/ShowBasic") );
588 OUString
instPath( getKey( xHierAccess
,"Path/Current/Help" ) );
589 if( instPath
.isEmpty() )
590 // try to determine path from default
591 instPath
= "$(instpath)/help";
593 // replace anything like $(instpath);
596 /**********************************************************************/
598 /**********************************************************************/
600 xHierAccess
= getHierAccess( sProvider
,
601 "org.openoffice.Setup" );
603 OUString
setupversion( getKey( xHierAccess
,"Product/ooSetupVersion" ) );
604 OUString setupextension
;
608 Reference
< lang::XMultiServiceFactory
> xConfigProvider
= theDefaultProvider::get( xContext
);
610 uno::Sequence
<uno::Any
> lParams(comphelper::InitAnyPropertySequence(
612 {"nodepath", uno::Any(OUString("/org.openoffice.Setup/Product"))}
616 uno::Reference
< uno::XInterface
> xCFG( xConfigProvider
->createInstanceWithArguments(
617 "com.sun.star.configuration.ConfigurationAccess",
620 uno::Reference
< container::XNameAccess
> xDirectAccess(xCFG
, uno::UNO_QUERY
);
621 uno::Any aRet
= xDirectAccess
->getByName("ooSetupExtension");
623 aRet
>>= setupextension
;
625 catch ( uno::Exception
& )
629 OUString
productVersion( setupversion
+ " " + setupextension
);
630 OUString
locale( getKey( xHierAccess
,"L10N/ooLocale" ) );
632 // Determine fileurl from url and locale
634 osl::FileBase::RC errFile
= osl::FileBase::getFileURLFromSystemPath( instPath
,url
);
635 if( errFile
!= osl::FileBase::E_None
) return configData
;
636 if( !url
.endsWith("/") )
640 osl::DirectoryItem aDirItem
;
641 if( osl::FileBase::E_None
== osl::DirectoryItem::get( url
+ locale
,aDirItem
) )
643 else if( ( ( idx
= locale
.indexOf( '-' ) ) != -1 ||
644 ( idx
= locale
.indexOf( '_' ) ) != -1 ) &&
645 osl::FileBase::E_None
== osl::DirectoryItem::get( url
+ locale
.subView( 0,idx
),
647 ret
= locale
.copy( 0,idx
);
655 // first of all, try do determine whether there are any *.tree files present
657 // Start with extensions to set them at the end of the list
658 TreeFileIterator
aTreeIt( locale
);
663 aTreeFile
= aTreeIt
.nextTreeFile( nFileSize
);
664 if( aTreeFile
.isEmpty() )
666 configData
.vFileLen
.push_back( nFileSize
);
667 configData
.vFileURL
.push_back( aTreeFile
);
670 osl::Directory
aDirectory( url
);
671 osl::FileStatus
aFileStatus(
672 osl_FileStatus_Mask_FileName
| osl_FileStatus_Mask_FileURL
);
673 if( osl::Directory::E_None
== aDirectory
.open() )
675 OUString aFileUrl
, aFileName
;
676 while( aDirectory
.getNextItem( aDirItem
) == osl::FileBase::E_None
&&
677 aDirItem
.getFileStatus( aFileStatus
) == osl::FileBase::E_None
&&
678 aFileStatus
.isValid( osl_FileStatus_Mask_FileURL
) &&
679 aFileStatus
.isValid( osl_FileStatus_Mask_FileName
) )
681 aFileUrl
= aFileStatus
.getFileURL();
682 aFileName
= aFileStatus
.getFileName();
683 int idx_
= aFileName
.lastIndexOf( '.' );
687 const sal_Unicode
* str
= aFileName
.getStr();
689 if( aFileName
.getLength() == idx_
+ 5 &&
690 ( str
[idx_
+ 1] == 't' || str
[idx_
+ 1] == 'T' ) &&
691 ( str
[idx_
+ 2] == 'r' || str
[idx_
+ 2] == 'R' ) &&
692 ( str
[idx_
+ 3] == 'e' || str
[idx_
+ 3] == 'E' ) &&
693 ( str
[idx_
+ 4] == 'e' || str
[idx_
+ 4] == 'E' ) )
695 OUString baseName
= aFileName
.copy(0,idx_
).toAsciiLowerCase();
696 if(! showBasic
&& baseName
== "sbasic" )
698 osl::File
aFile( aFileUrl
);
699 if( osl::FileBase::E_None
== aFile
.open( osl_File_OpenFlag_Read
) )
701 // use the file size, not aFileStatus size, in case the
702 // tree file is a symlink
704 aFile
.getSize( nSize
);
705 configData
.vFileLen
.push_back( nSize
);
706 configData
.vFileURL
.push_back( aFileUrl
);
714 configData
.m_vAdd
[0] = 12;
715 configData
.m_vAdd
[1] = 15;
716 configData
.m_vAdd
[2] = 11;
717 configData
.m_vAdd
[3] = 14;
718 configData
.m_vAdd
[4] = 12;
719 configData
.m_vReplacement
[0] = utl::ConfigManager::getProductName();
720 configData
.m_vReplacement
[1] = productVersion
;
721 // m_vReplacement[2...4] (vendorName/-Version/-Short) are empty strings
723 configData
.system
= system
;
724 configData
.locale
= locale
;
725 configData
.appendix
=
735 Reference
< XMultiServiceFactory
>
736 TVChildTarget::getConfiguration(const Reference
< XComponentContext
>& rxContext
)
738 Reference
< XMultiServiceFactory
> xProvider
;
743 xProvider
= theDefaultProvider::get( rxContext
);
745 catch( const css::uno::Exception
& )
747 OSL_ENSURE( xProvider
.is(),"can not instantiate configuration" );
754 Reference
< XHierarchicalNameAccess
>
755 TVChildTarget::getHierAccess( const Reference
< XMultiServiceFactory
>& sProvider
,
758 Reference
< XHierarchicalNameAccess
> xHierAccess
;
765 Reference
< XHierarchicalNameAccess
>
766 ( sProvider
->createInstanceWithArguments( "com.sun.star.configuration.ConfigurationAccess", { Any(OUString::createFromAscii(file
)) }),
769 catch( const css::uno::Exception
& )
778 TVChildTarget::getKey( const Reference
< XHierarchicalNameAccess
>& xHierAccess
,
782 if( xHierAccess
.is() )
788 xHierAccess
->getByHierarchicalName( OUString::createFromAscii( key
) );
790 catch( const css::container::NoSuchElementException
& )
799 TVChildTarget::getBooleanKey(const Reference
<
800 XHierarchicalNameAccess
>& xHierAccess
,
804 if( xHierAccess
.is() )
810 xHierAccess
->getByHierarchicalName(
811 OUString::createFromAscii(key
));
813 catch( const css::container::NoSuchElementException
& )
821 void TVChildTarget::subst( OUString
& instpath
)
823 SvtPathOptions aOptions
;
824 instpath
= aOptions
.SubstituteVariable( instpath
);
828 const char aHelpMediaType
[] = "application/vnd.sun.star.help";
830 TreeFileIterator::TreeFileIterator( OUString aLanguage
)
831 : m_eState( IteratorState::UserExtensions
)
832 , m_aLanguage(std::move( aLanguage
))
834 m_xContext
= ::comphelper::getProcessComponentContext();
835 if( !m_xContext
.is() )
837 throw RuntimeException( "TreeFileIterator::TreeFileIterator(), no XComponentContext" );
840 m_xSFA
= ucb::SimpleFileAccess::create(m_xContext
);
842 m_bUserPackagesLoaded
= false;
843 m_bSharedPackagesLoaded
= false;
844 m_bBundledPackagesLoaded
= false;
846 m_iSharedPackage
= 0;
847 m_iBundledPackage
= 0;
850 Reference
< deployment::XPackage
> TreeFileIterator::implGetHelpPackageFromPackage
851 ( const Reference
< deployment::XPackage
>& xPackage
, Reference
< deployment::XPackage
>& o_xParentPackageBundle
)
853 o_xParentPackageBundle
.clear();
855 Reference
< deployment::XPackage
> xHelpPackage
;
859 // Check if parent package is registered
860 beans::Optional
< beans::Ambiguous
<sal_Bool
> > option( xPackage
->isRegistered
861 ( Reference
<task::XAbortChannel
>(), Reference
<ucb::XCommandEnvironment
>() ) );
862 bool bRegistered
= false;
863 if( option
.IsPresent
)
865 beans::Ambiguous
<sal_Bool
> const & reg
= option
.Value
;
866 if( !reg
.IsAmbiguous
&& reg
.Value
)
872 if( xPackage
->isBundle() )
874 const Sequence
< Reference
< deployment::XPackage
> > aPkgSeq
= xPackage
->getBundle
875 ( Reference
<task::XAbortChannel
>(), Reference
<ucb::XCommandEnvironment
>() );
876 auto pSubPkg
= std::find_if(aPkgSeq
.begin(), aPkgSeq
.end(),
877 [](const Reference
< deployment::XPackage
>& xSubPkg
) {
878 const Reference
< deployment::XPackageTypeInfo
> xPackageTypeInfo
= xSubPkg
->getPackageType();
879 OUString aMediaType
= xPackageTypeInfo
->getMediaType();
880 return aMediaType
== aHelpMediaType
;
882 if (pSubPkg
!= aPkgSeq
.end())
884 xHelpPackage
= *pSubPkg
;
885 o_xParentPackageBundle
= xPackage
;
890 const Reference
< deployment::XPackageTypeInfo
> xPackageTypeInfo
= xPackage
->getPackageType();
891 OUString aMediaType
= xPackageTypeInfo
->getMediaType();
892 if( aMediaType
== aHelpMediaType
)
893 xHelpPackage
= xPackage
;
899 Reference
< deployment::XPackage
> TreeFileIterator::implGetNextUserHelpPackage
900 ( Reference
< deployment::XPackage
>& o_xParentPackageBundle
)
902 Reference
< deployment::XPackage
> xHelpPackage
;
904 if( !m_bUserPackagesLoaded
)
906 Reference
< XPackageManager
> xUserManager
=
907 thePackageManagerFactory::get( m_xContext
)->getPackageManager("user");
908 m_aUserPackagesSeq
= xUserManager
->getDeployedPackages
909 ( Reference
< task::XAbortChannel
>(), Reference
< ucb::XCommandEnvironment
>() );
911 m_bUserPackagesLoaded
= true;
914 if( m_iUserPackage
== m_aUserPackagesSeq
.getLength() )
916 m_eState
= IteratorState::SharedExtensions
; // Later: SHARED_MODULE
920 const Reference
< deployment::XPackage
>* pUserPackages
= m_aUserPackagesSeq
.getConstArray();
921 Reference
< deployment::XPackage
> xPackage
= pUserPackages
[ m_iUserPackage
++ ];
922 OSL_ENSURE( xPackage
.is(), "TreeFileIterator::implGetNextUserHelpPackage(): Invalid package" );
923 xHelpPackage
= implGetHelpPackageFromPackage( xPackage
, o_xParentPackageBundle
);
929 Reference
< deployment::XPackage
> TreeFileIterator::implGetNextSharedHelpPackage
930 ( Reference
< deployment::XPackage
>& o_xParentPackageBundle
)
932 Reference
< deployment::XPackage
> xHelpPackage
;
934 if( !m_bSharedPackagesLoaded
)
936 Reference
< XPackageManager
> xSharedManager
=
937 thePackageManagerFactory::get( m_xContext
)->getPackageManager("shared");
938 m_aSharedPackagesSeq
= xSharedManager
->getDeployedPackages
939 ( Reference
< task::XAbortChannel
>(), Reference
< ucb::XCommandEnvironment
>() );
941 m_bSharedPackagesLoaded
= true;
944 if( m_iSharedPackage
== m_aSharedPackagesSeq
.getLength() )
946 m_eState
= IteratorState::BundledExtensions
;
950 const Reference
< deployment::XPackage
>* pSharedPackages
= m_aSharedPackagesSeq
.getConstArray();
951 Reference
< deployment::XPackage
> xPackage
= pSharedPackages
[ m_iSharedPackage
++ ];
952 OSL_ENSURE( xPackage
.is(), "TreeFileIterator::implGetNextSharedHelpPackage(): Invalid package" );
953 xHelpPackage
= implGetHelpPackageFromPackage( xPackage
, o_xParentPackageBundle
);
959 Reference
< deployment::XPackage
> TreeFileIterator::implGetNextBundledHelpPackage
960 ( Reference
< deployment::XPackage
>& o_xParentPackageBundle
)
962 Reference
< deployment::XPackage
> xHelpPackage
;
964 if( !m_bBundledPackagesLoaded
)
966 Reference
< XPackageManager
> xBundledManager
=
967 thePackageManagerFactory::get( m_xContext
)->getPackageManager("bundled");
968 m_aBundledPackagesSeq
= xBundledManager
->getDeployedPackages
969 ( Reference
< task::XAbortChannel
>(), Reference
< ucb::XCommandEnvironment
>() );
971 m_bBundledPackagesLoaded
= true;
974 if( m_iBundledPackage
== m_aBundledPackagesSeq
.getLength() )
976 m_eState
= IteratorState::EndReached
;
980 const Reference
< deployment::XPackage
>* pBundledPackages
= m_aBundledPackagesSeq
.getConstArray();
981 Reference
< deployment::XPackage
> xPackage
= pBundledPackages
[ m_iBundledPackage
++ ];
982 OSL_ENSURE( xPackage
.is(), "TreeFileIterator::implGetNextBundledHelpPackage(): Invalid package" );
983 xHelpPackage
= implGetHelpPackageFromPackage( xPackage
, o_xParentPackageBundle
);
989 static bool isLetter( sal_Unicode c
)
991 return rtl::isAsciiAlpha(c
);
994 void TreeFileIterator::implGetLanguageVectorFromPackage( ::std::vector
< OUString
> &rv
,
995 const css::uno::Reference
< css::deployment::XPackage
>& xPackage
)
998 OUString aExtensionPath
= xPackage
->getURL();
999 const Sequence
< OUString
> aEntrySeq
= m_xSFA
->getFolderContents( aExtensionPath
, true );
1001 for( const OUString
& aEntry
: aEntrySeq
)
1003 if( m_xSFA
->isFolder( aEntry
) )
1005 sal_Int32 nLastSlash
= aEntry
.lastIndexOf( '/' );
1006 if( nLastSlash
!= -1 )
1008 OUString aPureEntry
= aEntry
.copy( nLastSlash
+ 1 );
1010 // Check language scheme
1011 int nLen
= aPureEntry
.getLength();
1012 const sal_Unicode
* pc
= aPureEntry
.getStr();
1013 bool bStartCanBeLanguage
= ( nLen
>= 2 && isLetter( pc
[0] ) && isLetter( pc
[1] ) );
1014 bool bIsLanguage
= bStartCanBeLanguage
&&
1015 ( nLen
== 2 || (nLen
== 5 && pc
[2] == '-' && isLetter( pc
[3] ) && isLetter( pc
[4] )) );
1017 rv
.push_back( aPureEntry
);
1024 OUString
TreeFileIterator::nextTreeFile( sal_Int32
& rnFileSize
)
1028 while( aRetFile
.isEmpty() && m_eState
!= IteratorState::EndReached
)
1032 case IteratorState::UserExtensions
:
1034 Reference
< deployment::XPackage
> xParentPackageBundle
;
1035 Reference
< deployment::XPackage
> xHelpPackage
= implGetNextUserHelpPackage( xParentPackageBundle
);
1036 if( !xHelpPackage
.is() )
1039 aRetFile
= implGetTreeFileFromPackage( rnFileSize
, xHelpPackage
);
1043 case IteratorState::SharedExtensions
:
1045 Reference
< deployment::XPackage
> xParentPackageBundle
;
1046 Reference
< deployment::XPackage
> xHelpPackage
= implGetNextSharedHelpPackage( xParentPackageBundle
);
1047 if( !xHelpPackage
.is() )
1050 aRetFile
= implGetTreeFileFromPackage( rnFileSize
, xHelpPackage
);
1053 case IteratorState::BundledExtensions
:
1055 Reference
< deployment::XPackage
> xParentPackageBundle
;
1056 Reference
< deployment::XPackage
> xHelpPackage
= implGetNextBundledHelpPackage( xParentPackageBundle
);
1057 if( !xHelpPackage
.is() )
1060 aRetFile
= implGetTreeFileFromPackage( rnFileSize
, xHelpPackage
);
1064 case IteratorState::EndReached
:
1065 OSL_FAIL( "DataBaseIterator::nextTreeFile(): Invalid case IteratorState::EndReached" );
1073 OUString
TreeFileIterator::expandURL( const OUString
& aURL
)
1075 static Reference
< util::XMacroExpander
> xMacroExpander
;
1076 static Reference
< uri::XUriReferenceFactory
> xFac
;
1078 std::scoped_lock
aGuard( m_aMutex
);
1080 if( !xMacroExpander
.is() || !xFac
.is() )
1082 xFac
= uri::UriReferenceFactory::create( m_xContext
);
1084 xMacroExpander
= util::theMacroExpander::get(m_xContext
);
1087 OUString aRetURL
= aURL
;
1088 Reference
< uri::XUriReference
> uriRef
;
1091 uriRef
= xFac
->parse( aRetURL
);
1094 Reference
< uri::XVndSunStarExpandUrl
> sxUri( uriRef
, UNO_QUERY
);
1098 aRetURL
= sxUri
->expand( xMacroExpander
);
1104 OUString
TreeFileIterator::implGetTreeFileFromPackage
1105 ( sal_Int32
& rnFileSize
, const Reference
< deployment::XPackage
>& xPackage
)
1108 OUString aLanguage
= m_aLanguage
;
1109 for( sal_Int32 iPass
= 0 ; iPass
< 2 ; ++iPass
)
1111 aRetFile
= expandURL( xPackage
->getURL() + "/" + aLanguage
+ "/help.tree" );
1114 if( m_xSFA
->exists( aRetFile
) )
1117 ::std::vector
< OUString
> av
;
1118 implGetLanguageVectorFromPackage( av
, xPackage
);
1119 ::std::vector
< OUString
>::const_iterator pFound
= LanguageTag::getFallback( av
, m_aLanguage
);
1120 if( pFound
!= av
.end() )
1121 aLanguage
= *pFound
;
1126 if( m_xSFA
->exists( aRetFile
) )
1127 rnFileSize
= m_xSFA
->getSize( aRetFile
);
1134 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */