LibreOffice Module xmlhelp (master) 1
tvread.cxx
Go to the documentation of this file.
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 <string.h>
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>
27#include <tvread.hxx>
28#include <expat.h>
29#include <osl/file.hxx>
31#include <com/sun/star/configuration/theDefaultProvider.hpp>
32#include <com/sun/star/ucb/SimpleFileAccess.hpp>
33
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>
42#include <memory>
43#include <utility>
44
45namespace treeview {
46
47 class TVDom
48 {
49 friend class TVChildTarget;
50 friend class TVRead;
51
52 public:
53
54 explicit TVDom( TVDom* arent = nullptr )
55 : kind( Kind::other ),
56 parent( arent ),
57 children( 0 )
58 {
59 }
60
62 {
63 children.emplace_back( new TVDom( this ) );
64 return children.back().get();
65 }
66
67 void newChild(std::unique_ptr<TVDom> p)
68 {
69 children.emplace_back(std::move(p));
70 children.back()->parent = this;
71 }
72
74 {
75 if( parent )
76 return parent;
77 else
78 return const_cast<TVDom*>(this); // I am my own parent, if I am the root
79 }
80
81 enum class Kind {
82 tree_node,
83 tree_leaf,
84 other
85 };
86
87 bool isLeaf() const { return kind == TVDom::Kind::tree_leaf; }
88 void setKind( Kind ind ) { kind = ind; }
89
90 void setApplication( const char* appl )
91 {
92 application = OUString( appl,
93 strlen( appl ),
94 RTL_TEXTENCODING_UTF8 );
95 }
96
97 void setTitle( const char* itle )
98 {
99 title += OUString( itle,
100 strlen( itle ),
101 RTL_TEXTENCODING_UTF8 );
102 }
103
104 void setTitle( const XML_Char* itle,int len )
105 {
106 title += OUString( itle,
107 len,
108 RTL_TEXTENCODING_UTF8 );
109 }
110
111 void setId( const char* d )
112 {
113 id = OUString( d,
114 strlen( d ),
115 RTL_TEXTENCODING_UTF8 );
116 }
117
118 void setAnchor( const char* nchor )
119 {
120 anchor = OUString( nchor,
121 strlen( nchor ),
122 RTL_TEXTENCODING_UTF8 );
123 }
124
125 OUString const & getTargetURL()
126 {
127 if( targetURL.isEmpty() )
128 {
129 targetURL = "vnd.sun.star.help://" + id;
130 }
131
132 return targetURL;
133 }
134
135 private:
136
138 OUString application;
139 OUString title;
140 OUString id;
141 OUString anchor;
142 OUString targetURL;
143
145 std::vector< std::unique_ptr<TVDom> > children;
146 };
147
148}
149
150using namespace treeview;
151using namespace com::sun::star;
152using namespace com::sun::star::uno;
153using namespace com::sun::star::beans;
154using namespace com::sun::star::configuration;
155using namespace com::sun::star::lang;
156using namespace com::sun::star::util;
157using namespace com::sun::star::container;
158using namespace com::sun::star::deployment;
159
160const char prodName[] = "%PRODUCTNAME";
161const char vendName[] = "%VENDORNAME";
162const char vendVersion[] = "%VENDORVERSION";
163const char vendShort[] = "%VENDORSHORT";
164const char prodVersion[] = "%PRODUCTVERSION";
165
166ConfigData::ConfigData()
167{
168}
169
170void ConfigData::replaceName( OUString& oustring ) const
171{
172 sal_Int32 idx = -1,k = 0,off;
173 bool cap = false;
174 OUStringBuffer aStrBuf( 0 );
175
176 while( ( idx = oustring.indexOf( '%', ++idx ) ) != -1 )
177 {
178 if( oustring.indexOf( prodName,idx ) == idx )
179 off = PRODUCTNAME;
180 else if( oustring.indexOf( prodVersion,idx ) == idx )
181 off = PRODUCTVERSION;
182 else if( oustring.indexOf( vendName,idx ) == idx )
183 off = VENDORNAME;
184 else if( oustring.indexOf( vendVersion,idx ) == idx )
185 off = VENDORVERSION;
186 else if( oustring.indexOf( vendShort,idx ) == idx )
187 off = VENDORSHORT;
188 else
189 off = -1;
190
191 if( off != -1 )
192 {
193 if( ! cap )
194 {
195 cap = true;
196 aStrBuf.ensureCapacity( 256 );
197 }
198
199 aStrBuf.append( &oustring.getStr()[k],idx - k );
200 aStrBuf.append( m_vReplacement[off] );
201 k = idx + m_vAdd[off];
202 }
203 }
204
205 if( cap )
206 {
207 if( k < oustring.getLength() )
208 aStrBuf.append( &oustring.getStr()[k],oustring.getLength()-k );
209 oustring = aStrBuf.makeStringAndClear();
210 }
211}
212
213// TVRead
214
215TVRead::TVRead( const ConfigData& configData,TVDom* tvDom )
216{
217 if( ! tvDom )
218 return;
219
220 Title = tvDom->title;
221 configData.replaceName( Title );
222 if( tvDom->isLeaf() )
223 {
224 TargetURL = tvDom->getTargetURL() + configData.appendix;
225 if( !tvDom->anchor.isEmpty() )
226 TargetURL += "#" + tvDom->anchor;
227 }
228 else
229 Children = new TVChildTarget( configData,tvDom );
230}
231
233{
234}
235
236// XNameAccess
237
238Any SAL_CALL
239TVRead::getByName( const OUString& aName )
240{
241 bool found( true );
242 Any aAny;
243 if( aName == "Title" )
244 aAny <<= Title;
245 else if( aName == "TargetURL" )
246 aAny <<= TargetURL;
247 else if( aName == "Children" )
248 {
250 aAny <<= Reference< XInterface >( p );
251 }
252 else
253 found = false;
254
255 if( found )
256 return aAny;
257
258 throw NoSuchElementException();
259}
260
263{
264 return { "Title", "TargetURL", "Children" };
265}
266
267sal_Bool SAL_CALL
268TVRead::hasByName( const OUString& aName )
269{
270 if( aName == "Title" ||
271 aName == "TargetURL" ||
272 aName == "Children" )
273 return true;
274
275 return false;
276}
277
278// XHierarchicalNameAccess
279
280Any SAL_CALL
281TVRead::getByHierarchicalName( const OUString& aName )
282{
283 OUString aRest;
284 if( aName.startsWith("Children/", &aRest) )
285 return Children->getByHierarchicalName( aRest );
286
287 return getByName( aName );
288}
289
290sal_Bool SAL_CALL
291TVRead::hasByHierarchicalName( const OUString& aName )
292{
293 OUString aRest;
294 if( aName.startsWith("Children/", &aRest) )
295 return Children->hasByHierarchicalName( aRest );
296
297 return hasByName( aName );
298}
299
300/**************************************************************************/
301/* */
302/* TVChildTarget */
303/* */
304/**************************************************************************/
305
306extern "C" {
307
308static void start_handler(void *userData,
309 const XML_Char *name,
310 const XML_Char **atts)
311{
312 TVDom::Kind kind;
313
314 if( strcmp( name,"help_section" ) == 0 ||
315 strcmp( name,"node" ) == 0 )
317 else if( strcmp( name,"topic" ) == 0 )
319 else
320 return;
321
322 TVDom **tvDom = static_cast< TVDom** >( userData );
323 TVDom *p;
324 p = *tvDom;
325
326 *tvDom = p->newChild();
327 p = *tvDom;
328
329 p->setKind( kind );
330 while( *atts )
331 {
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) );
340
341 atts+=2;
342 }
343}
344
345static void end_handler(void *userData,
346 SAL_UNUSED_PARAMETER const XML_Char * )
347{
348 TVDom **tvDom = static_cast< TVDom** >( userData );
349 *tvDom = (*tvDom)->getParent();
350}
351
352static void data_handler( void *userData,
353 const XML_Char *s,
354 int len)
355{
356 TVDom **tvDom = static_cast< TVDom** >( userData );
357 if( (*tvDom)->isLeaf() )
358 (*tvDom)->setTitle( s,len );
359}
360
361}
362
364{
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() );
368}
369
371{
372 ConfigData configData = init( xContext );
373
374 if( configData.locale.isEmpty() || configData.system.isEmpty() )
375 return;
376
377 sal_uInt64 ret,len = 0;
378 int j = configData.vFileURL.size();
379
380 TVDom tvDom;
381 TVDom* pTVDom = &tvDom;
382
383 while( j )
384 {
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 );
390 aFile.close();
391
392 XML_Parser parser = XML_ParserCreate( nullptr );
393 XML_SetElementHandler( parser,
395 end_handler );
396 XML_SetCharacterDataHandler( parser,
398 XML_SetUserData( parser,&pTVDom ); // does not return this
399
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");
403
404 XML_ParserFree( parser );
405
406 Check(pTVDom);
407 }
408 // now TVDom holds the relevant information
409
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() );
413}
414
416{
417}
418
420{
421 if (tvDom->children.empty())
422 {
423 return;
424 }
425
426 unsigned i = 0;
427 bool h = false;
428
429 while((i<tvDom->children.size()-1) && (!h))
430 {
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))
433 {
434 TVDom* p = tvDom->children.back().get();
435
436 for(auto & k : p->children)
437 {
438 std::unique_ptr<TVDom> tmp(SearchAndInsert(std::move(k), tvDom->children[i].get()));
439 if (tmp)
440 {
441 tvDom->children[i]->newChild(std::move(tmp));
442 }
443 }
444
445 tvDom->children.pop_back();
446 h = true;
447 }
448 ++i;
449 }
450}
451
452std::unique_ptr<TVDom>
453TVChildTarget::SearchAndInsert(std::unique_ptr<TVDom> p, TVDom* tvDom)
454{
455 if (p->isLeaf()) return p;
456
457 bool h = false;
458 sal_Int32 max = 0;
459
460 std::vector< std::unique_ptr<TVDom> >::iterator max_It, i;
461 max_It = tvDom->children.begin();
462
463 sal_Int32 c_int;
464 sal_Int32 p_int = p->id.toInt32();
465
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
470 {
471 h = true;
472 c_int = (*i)->id.toInt32();
473
474 if (p_int==c_int)
475 {
476 (*(tvDom->children.insert(i+1, std::move(p))))->parent = tvDom;
477 return nullptr;
478 }
479 else if(c_int>max && c_int < p_int)
480 {
481 max = c_int;
482 max_It = i+1;
483 }
484 }
485 if (h)
486 {
487 (*(tvDom->children.insert(max_It, std::move(p))))->parent = tvDom;
488 return nullptr;
489 }
490 else
491 {
492 for (auto& child : tvDom->children)
493 {
494 p = SearchAndInsert(std::move(p), child.get());
495 if (p == nullptr)
496 break;
497 }
498 return p;
499 }
500}
501
502Any SAL_CALL
503TVChildTarget::getByName( const OUString& aName )
504{
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();
509
511 return Any( Reference< XInterface >( p ) );
512}
513
516{
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 );
521
522 return seq;
523}
524
525sal_Bool SAL_CALL
526TVChildTarget::hasByName( const OUString& aName )
527{
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 ) )
531 return false;
532
533 return true;
534}
535
536// XHierarchicalNameAccess
537
538Any SAL_CALL
540{
541 sal_Int32 idx;
542
543 if( ( idx = aName.indexOf( '/' ) ) != -1 )
544 {
545 std::u16string_view num( aName.subView( 2, idx-4 ) );
546 sal_Int32 pref = o3tl::toInt32(num) - 1;
547
548 if( pref < 0 || Elements.size() <= o3tl::make_unsigned( pref ) )
549 throw NoSuchElementException();
550
551 return Elements[pref]->getByHierarchicalName( aName.copy( 1 + idx ) );
552 }
553 else
554 return getByName( aName );
555}
556
557sal_Bool SAL_CALL
559{
560 sal_Int32 idx;
561
562 if( ( idx = aName.indexOf( '/' ) ) != -1 )
563 {
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 ) )
567 return false;
568
569 return Elements[pref]->hasByHierarchicalName( aName.copy( 1 + idx ) );
570 }
571 else
572 return hasByName( aName );
573}
574
576{
577 ConfigData configData;
579
580 /**********************************************************************/
581 /* reading Office.Common */
582 /**********************************************************************/
583
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";
592
593 // replace anything like $(instpath);
594 subst( instPath );
595
596 /**********************************************************************/
597 /* reading setup */
598 /**********************************************************************/
599
600 xHierAccess = getHierAccess( sProvider,
601 "org.openoffice.Setup" );
602
603 OUString setupversion( getKey( xHierAccess,"Product/ooSetupVersion" ) );
604 OUString setupextension;
605
606 try
607 {
608 Reference< lang::XMultiServiceFactory > xConfigProvider = theDefaultProvider::get( xContext );
609
610 uno::Sequence<uno::Any> lParams(comphelper::InitAnyPropertySequence(
611 {
612 {"nodepath", uno::Any(OUString("/org.openoffice.Setup/Product"))}
613 }));
614
615 // open it
616 uno::Reference< uno::XInterface > xCFG( xConfigProvider->createInstanceWithArguments(
617 "com.sun.star.configuration.ConfigurationAccess",
618 lParams) );
619
620 uno::Reference< container::XNameAccess > xDirectAccess(xCFG, uno::UNO_QUERY);
621 uno::Any aRet = xDirectAccess->getByName("ooSetupExtension");
622
623 aRet >>= setupextension;
624 }
625 catch ( uno::Exception& )
626 {
627 }
628
629 OUString productVersion( setupversion + " " + setupextension );
630 OUString locale( getKey( xHierAccess,"L10N/ooLocale" ) );
631
632 // Determine fileurl from url and locale
633 OUString url;
634 osl::FileBase::RC errFile = osl::FileBase::getFileURLFromSystemPath( instPath,url );
635 if( errFile != osl::FileBase::E_None ) return configData;
636 if( !url.endsWith("/") )
637 url += "/";
638 OUString ret;
639 sal_Int32 idx;
640 osl::DirectoryItem aDirItem;
641 if( osl::FileBase::E_None == osl::DirectoryItem::get( url + locale,aDirItem ) )
642 ret = locale;
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 ),
646 aDirItem ) )
647 ret = locale.copy( 0,idx );
648 else
649 {
650 locale = "en-US";
651 ret = "en";
652 }
653 url += ret;
654
655 // first of all, try do determine whether there are any *.tree files present
656
657 // Start with extensions to set them at the end of the list
658 TreeFileIterator aTreeIt( locale );
659 OUString aTreeFile;
660 sal_Int32 nFileSize;
661 for (;;)
662 {
663 aTreeFile = aTreeIt.nextTreeFile( nFileSize );
664 if( aTreeFile.isEmpty() )
665 break;
666 configData.vFileLen.push_back( nFileSize );
667 configData.vFileURL.push_back( aTreeFile );
668 }
669
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() )
674 {
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 ) )
680 {
681 aFileUrl = aFileStatus.getFileURL();
682 aFileName = aFileStatus.getFileName();
683 int idx_ = aFileName.lastIndexOf( '.' );
684 if( idx_ == -1 )
685 continue;
686
687 const sal_Unicode* str = aFileName.getStr();
688
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' ) )
694 {
695 OUString baseName = aFileName.copy(0,idx_).toAsciiLowerCase();
696 if(! showBasic && baseName == "sbasic" )
697 continue;
698 osl::File aFile( aFileUrl );
699 if( osl::FileBase::E_None == aFile.open( osl_File_OpenFlag_Read ) )
700 {
701 // use the file size, not aFileStatus size, in case the
702 // tree file is a symlink
703 sal_uInt64 nSize;
704 aFile.getSize( nSize );
705 configData.vFileLen.push_back( nSize );
706 configData.vFileURL.push_back( aFileUrl );
707 aFile.close();
708 }
709 }
710 }
711 aDirectory.close();
712 }
713
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;
720 configData.m_vReplacement[1] = productVersion;
721 // m_vReplacement[2...4] (vendorName/-Version/-Short) are empty strings
722
723 configData.system = system;
724 configData.locale = locale;
725 configData.appendix =
726 "?Language=" +
727 configData.locale +
728 "&System=" +
729 configData.system +
730 "&UseDB=no";
731
732 return configData;
733}
734
737{
739 if( rxContext.is() )
740 {
741 try
742 {
743 xProvider = theDefaultProvider::get( rxContext );
744 }
745 catch( const css::uno::Exception& )
746 {
747 OSL_ENSURE( xProvider.is(),"can not instantiate configuration" );
748 }
749 }
750
751 return xProvider;
752}
753
756 const char* file )
757{
759
760 if( sProvider.is() )
761 {
762 try
763 {
764 xHierAccess =
766 ( sProvider->createInstanceWithArguments( "com.sun.star.configuration.ConfigurationAccess", { Any(OUString::createFromAscii(file)) }),
767 UNO_QUERY );
768 }
769 catch( const css::uno::Exception& )
770 {
771 }
772 }
773
774 return xHierAccess;
775}
776
777OUString
779 const char* key )
780{
781 OUString instPath;
782 if( xHierAccess.is() )
783 {
784 Any aAny;
785 try
786 {
787 aAny =
788 xHierAccess->getByHierarchicalName( OUString::createFromAscii( key ) );
789 }
790 catch( const css::container::NoSuchElementException& )
791 {
792 }
793 aAny >>= instPath;
794 }
795 return instPath;
796}
797
798bool
800 XHierarchicalNameAccess >& xHierAccess,
801 const char* key)
802{
803 bool ret = false;
804 if( xHierAccess.is() )
805 {
806 Any aAny;
807 try
808 {
809 aAny =
810 xHierAccess->getByHierarchicalName(
811 OUString::createFromAscii(key));
812 }
813 catch( const css::container::NoSuchElementException& )
814 {
815 }
816 aAny >>= ret;
817 }
818 return ret;
819}
820
821void TVChildTarget::subst( OUString& instpath )
822{
823 SvtPathOptions aOptions;
824 instpath = aOptions.SubstituteVariable( instpath );
825}
826
827
828const char aHelpMediaType[] = "application/vnd.sun.star.help";
829
831 : m_eState( IteratorState::UserExtensions )
832 , m_aLanguage(std::move( aLanguage ))
833{
834 m_xContext = ::comphelper::getProcessComponentContext();
835 if( !m_xContext.is() )
836 {
837 throw RuntimeException( "TreeFileIterator::TreeFileIterator(), no XComponentContext" );
838 }
839
840 m_xSFA = ucb::SimpleFileAccess::create(m_xContext);
841
842 m_bUserPackagesLoaded = false;
845 m_iUserPackage = 0;
848}
849
851 ( const Reference< deployment::XPackage >& xPackage, Reference< deployment::XPackage >& o_xParentPackageBundle )
852{
853 o_xParentPackageBundle.clear();
854
856 if( !xPackage.is() )
857 return xHelpPackage;
858
859 // Check if parent package is registered
860 beans::Optional< beans::Ambiguous<sal_Bool> > option( xPackage->isRegistered
862 bool bRegistered = false;
863 if( option.IsPresent )
864 {
865 beans::Ambiguous<sal_Bool> const & reg = option.Value;
866 if( !reg.IsAmbiguous && reg.Value )
867 bRegistered = true;
868 }
869 if( !bRegistered )
870 return xHelpPackage;
871
872 if( xPackage->isBundle() )
873 {
874 const Sequence< Reference< deployment::XPackage > > aPkgSeq = xPackage->getBundle
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;
881 });
882 if (pSubPkg != aPkgSeq.end())
883 {
884 xHelpPackage = *pSubPkg;
885 o_xParentPackageBundle = xPackage;
886 }
887 }
888 else
889 {
890 const Reference< deployment::XPackageTypeInfo > xPackageTypeInfo = xPackage->getPackageType();
891 OUString aMediaType = xPackageTypeInfo->getMediaType();
892 if( aMediaType == aHelpMediaType )
893 xHelpPackage = xPackage;
894 }
895
896 return xHelpPackage;
897}
898
900 ( Reference< deployment::XPackage >& o_xParentPackageBundle )
901{
903
905 {
906 Reference< XPackageManager > xUserManager =
907 thePackageManagerFactory::get( m_xContext )->getPackageManager("user");
908 m_aUserPackagesSeq = xUserManager->getDeployedPackages
910
912 }
913
914 if( m_iUserPackage == m_aUserPackagesSeq.getLength() )
915 {
916 m_eState = IteratorState::SharedExtensions; // Later: SHARED_MODULE
917 }
918 else
919 {
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 );
924 }
925
926 return xHelpPackage;
927}
928
930 ( Reference< deployment::XPackage >& o_xParentPackageBundle )
931{
933
935 {
936 Reference< XPackageManager > xSharedManager =
937 thePackageManagerFactory::get( m_xContext )->getPackageManager("shared");
938 m_aSharedPackagesSeq = xSharedManager->getDeployedPackages
940
942 }
943
944 if( m_iSharedPackage == m_aSharedPackagesSeq.getLength() )
945 {
947 }
948 else
949 {
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 );
954 }
955
956 return xHelpPackage;
957}
958
960 ( Reference< deployment::XPackage >& o_xParentPackageBundle )
961{
963
965 {
966 Reference< XPackageManager > xBundledManager =
967 thePackageManagerFactory::get( m_xContext )->getPackageManager("bundled");
968 m_aBundledPackagesSeq = xBundledManager->getDeployedPackages
970
972 }
973
974 if( m_iBundledPackage == m_aBundledPackagesSeq.getLength() )
975 {
977 }
978 else
979 {
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 );
984 }
985
986 return xHelpPackage;
987}
988
989static bool isLetter( sal_Unicode c )
990{
991 return rtl::isAsciiAlpha(c);
992}
993
994void TreeFileIterator::implGetLanguageVectorFromPackage( ::std::vector< OUString > &rv,
995 const css::uno::Reference< css::deployment::XPackage >& xPackage )
996{
997 rv.clear();
998 OUString aExtensionPath = xPackage->getURL();
999 const Sequence< OUString > aEntrySeq = m_xSFA->getFolderContents( aExtensionPath, true );
1000
1001 for( const OUString& aEntry : aEntrySeq )
1002 {
1003 if( m_xSFA->isFolder( aEntry ) )
1004 {
1005 sal_Int32 nLastSlash = aEntry.lastIndexOf( '/' );
1006 if( nLastSlash != -1 )
1007 {
1008 OUString aPureEntry = aEntry.copy( nLastSlash + 1 );
1009
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] )) );
1016 if( bIsLanguage )
1017 rv.push_back( aPureEntry );
1018 }
1019 }
1020 }
1021}
1022
1023
1024OUString TreeFileIterator::nextTreeFile( sal_Int32& rnFileSize )
1025{
1026 OUString aRetFile;
1027
1028 while( aRetFile.isEmpty() && m_eState != IteratorState::EndReached )
1029 {
1030 switch( m_eState )
1031 {
1033 {
1034 Reference< deployment::XPackage > xParentPackageBundle;
1035 Reference< deployment::XPackage > xHelpPackage = implGetNextUserHelpPackage( xParentPackageBundle );
1036 if( !xHelpPackage.is() )
1037 break;
1038
1039 aRetFile = implGetTreeFileFromPackage( rnFileSize, xHelpPackage );
1040 break;
1041 }
1042
1044 {
1045 Reference< deployment::XPackage > xParentPackageBundle;
1046 Reference< deployment::XPackage > xHelpPackage = implGetNextSharedHelpPackage( xParentPackageBundle );
1047 if( !xHelpPackage.is() )
1048 break;
1049
1050 aRetFile = implGetTreeFileFromPackage( rnFileSize, xHelpPackage );
1051 break;
1052 }
1054 {
1055 Reference< deployment::XPackage > xParentPackageBundle;
1056 Reference< deployment::XPackage > xHelpPackage = implGetNextBundledHelpPackage( xParentPackageBundle );
1057 if( !xHelpPackage.is() )
1058 break;
1059
1060 aRetFile = implGetTreeFileFromPackage( rnFileSize, xHelpPackage );
1061 break;
1062 }
1063
1065 OSL_FAIL( "DataBaseIterator::nextTreeFile(): Invalid case IteratorState::EndReached" );
1066 break;
1067 }
1068 }
1069
1070 return aRetFile;
1071}
1072
1073OUString TreeFileIterator::expandURL( const OUString& aURL )
1074{
1075 static Reference< util::XMacroExpander > xMacroExpander;
1077
1078 std::scoped_lock aGuard( m_aMutex );
1079
1080 if( !xMacroExpander.is() || !xFac.is() )
1081 {
1082 xFac = uri::UriReferenceFactory::create( m_xContext );
1083
1084 xMacroExpander = util::theMacroExpander::get(m_xContext);
1085 }
1086
1087 OUString aRetURL = aURL;
1089 for (;;)
1090 {
1091 uriRef = xFac->parse( aRetURL );
1092 if ( uriRef.is() )
1093 {
1094 Reference < uri::XVndSunStarExpandUrl > sxUri( uriRef, UNO_QUERY );
1095 if( !sxUri.is() )
1096 break;
1097
1098 aRetURL = sxUri->expand( xMacroExpander );
1099 }
1100 }
1101 return aRetURL;
1102}
1103
1105 ( sal_Int32& rnFileSize, const Reference< deployment::XPackage >& xPackage )
1106{
1107 OUString aRetFile;
1108 OUString aLanguage = m_aLanguage;
1109 for( sal_Int32 iPass = 0 ; iPass < 2 ; ++iPass )
1110 {
1111 aRetFile = expandURL( xPackage->getURL() + "/" + aLanguage + "/help.tree" );
1112 if( iPass == 0 )
1113 {
1114 if( m_xSFA->exists( aRetFile ) )
1115 break;
1116
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;
1122 }
1123 }
1124
1125 rnFileSize = 0;
1126 if( m_xSFA->exists( aRetFile ) )
1127 rnFileSize = m_xSFA->getSize( aRetFile );
1128 else
1129 aRetFile.clear();
1130
1131 return aRetFile;
1132}
1133
1134/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
double d
::std::vector< OUString >::const_iterator getFallback(const ::std::vector< OUString > &rList, const OUString &rReference)
OUString SubstituteVariable(const OUString &rVar) const
void replaceName(OUString &oustring) const
Definition: tvread.cxx:170
std::vector< OUString > vFileURL
Definition: tvread.hxx:51
OUString appendix
Definition: tvread.hxx:53
std::vector< sal_uInt64 > vFileLen
Definition: tvread.hxx:50
OUString m_vReplacement[5]
Definition: tvread.hxx:48
friend class TVChildTarget
Definition: tvread.hxx:67
static css::uno::Reference< css::container::XHierarchicalNameAccess > getHierAccess(const css::uno::Reference< css::lang::XMultiServiceFactory > &rxProvider, const char *file)
Definition: tvread.cxx:755
static void subst(OUString &instpath)
Definition: tvread.cxx:821
virtual css::uno::Any SAL_CALL getByHierarchicalName(const OUString &aName) override
Definition: tvread.cxx:539
std::unique_ptr< TVDom > SearchAndInsert(std::unique_ptr< TVDom > p, TVDom *tvDom)
Definition: tvread.cxx:453
virtual ~TVChildTarget() override
Definition: tvread.cxx:415
void Check(TVDom *tvDom)
Definition: tvread.cxx:419
static OUString getKey(const css::uno::Reference< css::container::XHierarchicalNameAccess > &xHierAccess, const char *key)
Definition: tvread.cxx:778
virtual css::uno::Any SAL_CALL getByName(const OUString &aName) override
Definition: tvread.cxx:503
virtual css::uno::Sequence< OUString > SAL_CALL getElementNames() override
Definition: tvread.cxx:515
static css::uno::Reference< css::lang::XMultiServiceFactory > getConfiguration(const css::uno::Reference< css::uno::XComponentContext > &rxContext)
Definition: tvread.cxx:736
static ConfigData init(const css::uno::Reference< css::uno::XComponentContext > &xContext)
Definition: tvread.cxx:575
virtual sal_Bool SAL_CALL hasByName(const OUString &aName) override
Definition: tvread.cxx:526
virtual sal_Bool SAL_CALL hasByHierarchicalName(const OUString &aName) override
Definition: tvread.cxx:558
std::vector< rtl::Reference< TVRead > > Elements
Definition: tvread.hxx:203
static bool getBooleanKey(const css::uno::Reference< css::container::XHierarchicalNameAccess > &xHierAccess, const char *key)
Definition: tvread.cxx:799
std::vector< std::unique_ptr< TVDom > > children
Definition: tvread.cxx:145
void setTitle(const XML_Char *itle, int len)
Definition: tvread.cxx:104
TVDom * newChild()
Definition: tvread.cxx:61
void setTitle(const char *itle)
Definition: tvread.cxx:97
TVDom * parent
Definition: tvread.cxx:144
void setAnchor(const char *nchor)
Definition: tvread.cxx:118
OUString title
Definition: tvread.cxx:139
OUString targetURL
Definition: tvread.cxx:142
void setApplication(const char *appl)
Definition: tvread.cxx:90
TVDom * getParent() const
Definition: tvread.cxx:73
OUString anchor
Definition: tvread.cxx:141
OUString application
Definition: tvread.cxx:138
bool isLeaf() const
Definition: tvread.cxx:87
OUString id
Definition: tvread.cxx:140
OUString const & getTargetURL()
Definition: tvread.cxx:125
void newChild(std::unique_ptr< TVDom > p)
Definition: tvread.cxx:67
void setKind(Kind ind)
Definition: tvread.cxx:88
TVDom(TVDom *arent=nullptr)
Definition: tvread.cxx:54
void setId(const char *d)
Definition: tvread.cxx:111
TVRead(const ConfigData &configData, TVDom *tvDom)
Definition: tvread.cxx:215
virtual css::uno::Any SAL_CALL getByHierarchicalName(const OUString &aName) override
Definition: tvread.cxx:281
virtual ~TVRead() override
Definition: tvread.cxx:232
OUString TargetURL
Definition: tvread.hxx:169
virtual css::uno::Any SAL_CALL getByName(const OUString &aName) override
Definition: tvread.cxx:239
rtl::Reference< TVChildTarget > Children
Definition: tvread.hxx:170
virtual css::uno::Sequence< OUString > SAL_CALL getElementNames() override
Definition: tvread.cxx:262
friend class TVChildTarget
Definition: tvread.hxx:140
OUString Title
Definition: tvread.hxx:168
virtual sal_Bool SAL_CALL hasByName(const OUString &aName) override
Definition: tvread.cxx:268
virtual sal_Bool SAL_CALL hasByHierarchicalName(const OUString &aName) override
Definition: tvread.cxx:291
TreeFileIterator(OUString aLanguage)
Definition: tvread.cxx:830
css::uno::Sequence< css::uno::Reference< css::deployment::XPackage > > m_aSharedPackagesSeq
Definition: tvread.hxx:274
OUString expandURL(const OUString &aURL)
Definition: tvread.cxx:1073
css::uno::Sequence< css::uno::Reference< css::deployment::XPackage > > m_aBundledPackagesSeq
Definition: tvread.hxx:278
css::uno::Reference< css::uno::XComponentContext > m_xContext
Definition: tvread.hxx:263
OUString nextTreeFile(sal_Int32 &rnFileSize)
Definition: tvread.cxx:1024
css::uno::Reference< css::deployment::XPackage > implGetNextSharedHelpPackage(css::uno::Reference< css::deployment::XPackage > &o_xParentPackageBundle)
Definition: tvread.cxx:930
static css::uno::Reference< css::deployment::XPackage > implGetHelpPackageFromPackage(const css::uno::Reference< css::deployment::XPackage > &xPackage, css::uno::Reference< css::deployment::XPackage > &o_xParentPackageBundle)
Definition: tvread.cxx:851
css::uno::Reference< css::deployment::XPackage > implGetNextUserHelpPackage(css::uno::Reference< css::deployment::XPackage > &o_xParentPackageBundle)
Definition: tvread.cxx:900
void implGetLanguageVectorFromPackage(::std::vector< OUString > &rv, const css::uno::Reference< css::deployment::XPackage > &xPackage)
Definition: tvread.cxx:994
css::uno::Reference< css::deployment::XPackage > implGetNextBundledHelpPackage(css::uno::Reference< css::deployment::XPackage > &o_xParentPackageBundle)
Definition: tvread.cxx:960
css::uno::Sequence< css::uno::Reference< css::deployment::XPackage > > m_aUserPackagesSeq
Definition: tvread.hxx:270
IteratorState m_eState
Definition: tvread.hxx:266
css::uno::Reference< css::ucb::XSimpleFileAccess3 > m_xSFA
Definition: tvread.hxx:264
OUString implGetTreeFileFromPackage(sal_Int32 &rnFileSize, const css::uno::Reference< css::deployment::XPackage > &xPackage)
Definition: tvread.cxx:1105
static OUString getProductName()
URL aURL
float u
#define max(a, b)
anchor
const char * name
const sal_uInt16 idx[]
OUString aName
void * p
#define SAL_WARN_IF(condition, area, stream)
css::uno::Sequence< css::uno::Any > InitAnyPropertySequence(::std::initializer_list< ::std::pair< OUString, css::uno::Any > > vInit)
int i
constexpr std::enable_if_t< std::is_signed_v< T >, std::make_unsigned_t< T > > make_unsigned(T value)
sal_Int32 toInt32(std::u16string_view str, sal_Int16 radix=10)
parser
IteratorState
Definition: tvread.hxx:234
sal_Int32 h
JCOPY_OPTION option
static void start_handler(void *userData, const XML_Char *name, const XML_Char **atts)
Definition: tvread.cxx:308
const char vendVersion[]
Definition: tvread.cxx:162
const char prodName[]
Definition: tvread.cxx:160
const char prodVersion[]
Definition: tvread.cxx:164
static bool isLetter(sal_Unicode c)
Definition: tvread.cxx:989
const char vendName[]
Definition: tvread.cxx:161
const char aHelpMediaType[]
Definition: tvread.cxx:828
static void data_handler(void *userData, const XML_Char *s, int len)
Definition: tvread.cxx:352
static void end_handler(void *userData, SAL_UNUSED_PARAMETER const XML_Char *)
Definition: tvread.cxx:345
const char vendShort[]
Definition: tvread.cxx:163
unsigned char sal_Bool
sal_uInt16 sal_Unicode