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 <string.h>
21 : #include <rtl/ustrbuf.hxx>
22 : #include <osl/diagnose.h>
23 : #include "tvread.hxx"
24 : #include <expat.h>
25 : #include <osl/file.hxx>
26 : #include <unotools/configmgr.hxx>
27 : #include <com/sun/star/configuration/theDefaultProvider.hpp>
28 : #include <com/sun/star/ucb/SimpleFileAccess.hpp>
29 : #include <com/sun/star/frame/XConfigManager.hpp>
30 : #include <com/sun/star/beans/PropertyValue.hpp>
31 :
32 : #include <comphelper/processfactory.hxx>
33 : #include <com/sun/star/deployment/thePackageManagerFactory.hpp>
34 : #include <com/sun/star/util/theMacroExpander.hpp>
35 : #include <com/sun/star/uri/UriReferenceFactory.hpp>
36 : #include <com/sun/star/uri/XVndSunStarExpandUrl.hpp>
37 : #include <i18nlangtag/languagetag.hxx>
38 : #include <comphelper/string.hxx>
39 : #include <unotools/pathoptions.hxx>
40 :
41 : namespace treeview {
42 :
43 : class TVDom
44 : {
45 : friend class TVChildTarget;
46 : friend class TVRead;
47 :
48 : public:
49 :
50 0 : explicit TVDom( TVDom* arent = 0 )
51 : : kind( other ),
52 : parent( arent ),
53 0 : children( 0 )
54 : {
55 0 : }
56 :
57 0 : ~TVDom()
58 0 : {
59 0 : for( size_t i = 0; i < children.size(); ++i )
60 0 : delete children[i];
61 0 : }
62 :
63 0 : TVDom* newChild()
64 : {
65 0 : children.push_back( new TVDom( this ) );
66 0 : return children.back();
67 : }
68 :
69 0 : TVDom* newChild(TVDom* p)
70 : {
71 0 : children.push_back( p );
72 0 : p->parent = this;
73 0 : return children.back();
74 : }
75 :
76 0 : TVDom* getParent() const
77 : {
78 0 : if( parent )
79 0 : return parent;
80 : else
81 0 : return const_cast<TVDom*>(this); // I am my own parent, if I am the root
82 : }
83 :
84 : enum Kind {
85 : tree_view,
86 : tree_node,
87 : tree_leaf,
88 : other
89 : };
90 :
91 0 : bool isLeaf() const { return kind == TVDom::tree_leaf; }
92 0 : void setKind( Kind ind ) { kind = ind; }
93 :
94 0 : void setApplication( const char* appl )
95 : {
96 0 : application = OUString( appl,
97 0 : strlen( appl ),
98 0 : RTL_TEXTENCODING_UTF8 );
99 0 : }
100 :
101 0 : void setTitle( const char* itle )
102 : {
103 0 : title += OUString( itle,
104 0 : strlen( itle ),
105 0 : RTL_TEXTENCODING_UTF8 );
106 0 : }
107 :
108 0 : void setTitle( const XML_Char* itle,int len )
109 : {
110 0 : title += OUString( itle,
111 : len,
112 0 : RTL_TEXTENCODING_UTF8 );
113 0 : }
114 :
115 0 : void setId( const char* d )
116 : {
117 0 : id = OUString( d,
118 0 : strlen( d ),
119 0 : RTL_TEXTENCODING_UTF8 );
120 0 : }
121 :
122 0 : void setAnchor( const char* nchor )
123 : {
124 0 : anchor = OUString( nchor,
125 0 : strlen( nchor ),
126 0 : RTL_TEXTENCODING_UTF8 );
127 0 : }
128 :
129 0 : OUString getTargetURL()
130 : {
131 0 : if( targetURL.isEmpty() )
132 : {
133 : sal_Int32 len;
134 0 : for ( const TVDom* p = this;; p = p->parent )
135 : {
136 0 : len = p->application.getLength();
137 0 : if ( len != 0 )
138 0 : break;
139 0 : }
140 :
141 0 : OUStringBuffer strBuff( 22 + len + id.getLength() );
142 : strBuff.appendAscii(
143 : "vnd.sun.star.help://"
144 0 : ).append(id);
145 :
146 0 : targetURL = strBuff.makeStringAndClear();
147 : }
148 :
149 0 : return targetURL;
150 : }
151 :
152 : private:
153 :
154 : Kind kind;
155 : OUString application;
156 : OUString title;
157 : OUString id;
158 : OUString anchor;
159 : OUString targetURL;
160 :
161 : TVDom *parent;
162 : std::vector< TVDom* > children;
163 : };
164 :
165 : }
166 :
167 : using namespace treeview;
168 : using namespace com::sun::star;
169 : using namespace com::sun::star::uno;
170 : using namespace com::sun::star::beans;
171 : using namespace com::sun::star::configuration;
172 : using namespace com::sun::star::lang;
173 : using namespace com::sun::star::util;
174 : using namespace com::sun::star::frame;
175 : using namespace com::sun::star::container;
176 : using namespace com::sun::star::deployment;
177 :
178 0 : ConfigData::ConfigData()
179 : : prodName("%PRODUCTNAME"),
180 : prodVersion("%PRODUCTVERSION"),
181 : vendName("%VENDORNAME"),
182 : vendVersion("%VENDORVERSION"),
183 0 : vendShort("%VENDORSHORT")
184 : {
185 0 : memset(m_vAdd, 0, sizeof(m_vAdd));
186 0 : }
187 :
188 0 : void SAL_CALL ConfigData::replaceName( OUString& oustring ) const
189 : {
190 0 : sal_Int32 idx = -1,k = 0,off;
191 0 : bool cap = false;
192 0 : OUStringBuffer aStrBuf( 0 );
193 :
194 0 : while( ( idx = oustring.indexOf( '%', ++idx ) ) != -1 )
195 : {
196 0 : if( oustring.indexOf( prodName,idx ) == idx )
197 0 : off = PRODUCTNAME;
198 0 : else if( oustring.indexOf( prodVersion,idx ) == idx )
199 0 : off = PRODUCTVERSION;
200 0 : else if( oustring.indexOf( vendName,idx ) == idx )
201 0 : off = VENDORNAME;
202 0 : else if( oustring.indexOf( vendVersion,idx ) == idx )
203 0 : off = VENDORVERSION;
204 0 : else if( oustring.indexOf( vendShort,idx ) == idx )
205 0 : off = VENDORSHORT;
206 : else
207 0 : off = -1;
208 :
209 0 : if( off != -1 )
210 : {
211 0 : if( ! cap )
212 : {
213 0 : cap = true;
214 0 : aStrBuf.ensureCapacity( 256 );
215 : }
216 :
217 0 : aStrBuf.append( &oustring.getStr()[k],idx - k );
218 0 : aStrBuf.append( m_vReplacement[off] );
219 0 : k = idx + m_vAdd[off];
220 : }
221 : }
222 :
223 0 : if( cap )
224 : {
225 0 : if( k < oustring.getLength() )
226 0 : aStrBuf.append( &oustring.getStr()[k],oustring.getLength()-k );
227 0 : oustring = aStrBuf.makeStringAndClear();
228 0 : }
229 0 : }
230 :
231 : // TVRead
232 :
233 0 : TVRead::TVRead( const ConfigData& configData,TVDom* tvDom )
234 : {
235 0 : if( ! tvDom )
236 0 : return;
237 :
238 0 : Title = tvDom->title;
239 0 : configData.replaceName( Title );
240 0 : if( tvDom->isLeaf() )
241 : {
242 0 : TargetURL = ( tvDom->getTargetURL() + configData.appendix );
243 0 : if( !tvDom->anchor.isEmpty() )
244 0 : TargetURL += "#" + tvDom->anchor;
245 : }
246 : else
247 0 : Children = new TVChildTarget( configData,tvDom );
248 : }
249 :
250 0 : TVRead::~TVRead()
251 : {
252 0 : }
253 :
254 : // XNameAccess
255 :
256 : Any SAL_CALL
257 0 : TVRead::getByName( const OUString& aName )
258 : throw( NoSuchElementException,
259 : WrappedTargetException,
260 : RuntimeException, std::exception )
261 : {
262 0 : bool found( true );
263 0 : Any aAny;
264 0 : if( aName == "Title" )
265 0 : aAny <<= Title;
266 0 : else if( aName == "TargetURL" )
267 0 : aAny <<= TargetURL;
268 0 : else if( aName == "Children" )
269 : {
270 0 : cppu::OWeakObject* p = Children.get();
271 0 : aAny <<= Reference< XInterface >( p );
272 : }
273 : else
274 0 : found = false;
275 :
276 0 : if( found )
277 0 : return aAny;
278 :
279 0 : throw NoSuchElementException();
280 : }
281 :
282 : Sequence< OUString > SAL_CALL
283 0 : TVRead::getElementNames( )
284 : throw( RuntimeException, std::exception )
285 : {
286 0 : Sequence< OUString > seq( 3 );
287 :
288 0 : seq[0] = "Title";
289 0 : seq[1] = "TargetURL";
290 0 : seq[2] = "Children";
291 :
292 0 : return seq;
293 : }
294 :
295 : sal_Bool SAL_CALL
296 0 : TVRead::hasByName( const OUString& aName )
297 : throw( RuntimeException, std::exception )
298 : {
299 0 : if( aName == "Title" ||
300 0 : aName == "TargetURL" ||
301 0 : aName == "Children" )
302 0 : return true;
303 :
304 0 : return false;
305 : }
306 :
307 : // XHierarchicalNameAccess
308 :
309 : Any SAL_CALL
310 0 : TVRead::getByHierarchicalName( const OUString& aName )
311 : throw( NoSuchElementException,
312 : RuntimeException, std::exception )
313 : {
314 : sal_Int32 idx;
315 0 : OUString name( aName );
316 :
317 0 : if( ( idx = name.indexOf( '/' ) ) != -1 &&
318 0 : name.copy( 0,idx ) == "Children" )
319 0 : return Children->getByHierarchicalName( name.copy( 1 + idx ) );
320 :
321 0 : return getByName( name );
322 : }
323 :
324 : sal_Bool SAL_CALL
325 0 : TVRead::hasByHierarchicalName( const OUString& aName )
326 : throw( RuntimeException, std::exception )
327 : {
328 : sal_Int32 idx;
329 0 : OUString name( aName );
330 :
331 0 : if( ( idx = name.indexOf( '/' ) ) != -1 &&
332 0 : name.copy( 0,idx ) == "Children" )
333 0 : return Children->hasByHierarchicalName( name.copy( 1 + idx ) );
334 :
335 0 : return hasByName( name );
336 : }
337 :
338 : /**************************************************************************/
339 : /* */
340 : /* TVChildTarget */
341 : /* */
342 : /**************************************************************************/
343 :
344 0 : extern "C" void start_handler(void *userData,
345 : const XML_Char *name,
346 : const XML_Char **atts)
347 : {
348 : TVDom::Kind kind;
349 :
350 0 : if( strcmp( name,"help_section" ) == 0 ||
351 0 : strcmp( name,"node" ) == 0 )
352 0 : kind = TVDom::tree_node;
353 0 : else if( strcmp( name,"topic" ) == 0 )
354 0 : kind = TVDom::tree_leaf;
355 : else
356 0 : return;
357 :
358 0 : TVDom **tvDom = static_cast< TVDom** >( userData );
359 : TVDom *p;
360 0 : p = *tvDom;
361 :
362 0 : *tvDom = p->newChild();
363 0 : p = *tvDom;
364 :
365 0 : p->setKind( kind );
366 0 : while( *atts )
367 : {
368 0 : if( strcmp( *atts,"application" ) == 0 )
369 0 : p->setApplication( *(atts+1) );
370 0 : else if( strcmp( *atts,"title" ) == 0 )
371 0 : p->setTitle( *(atts+1) );
372 0 : else if( strcmp( *atts,"id" ) == 0 )
373 0 : p->setId( *(atts+1) );
374 0 : else if( strcmp( *atts,"anchor" ) == 0 )
375 0 : p->setAnchor( *(atts+1) );
376 :
377 0 : atts+=2;
378 : }
379 : }
380 :
381 0 : extern "C" void end_handler(void *userData,
382 : const XML_Char *name )
383 : {
384 : (void)name;
385 :
386 0 : TVDom **tvDom = static_cast< TVDom** >( userData );
387 0 : *tvDom = (*tvDom)->getParent();
388 0 : }
389 :
390 0 : extern "C" void data_handler( void *userData,
391 : const XML_Char *s,
392 : int len)
393 : {
394 0 : TVDom **tvDom = static_cast< TVDom** >( userData );
395 0 : if( (*tvDom)->isLeaf() )
396 0 : (*tvDom)->setTitle( s,len );
397 0 : }
398 :
399 0 : TVChildTarget::TVChildTarget( const ConfigData& configData,TVDom* tvDom )
400 : {
401 0 : Elements.resize( tvDom->children.size() );
402 0 : for( size_t i = 0; i < Elements.size(); ++i )
403 0 : Elements[i] = new TVRead( configData,tvDom->children[i] );
404 0 : }
405 :
406 0 : TVChildTarget::TVChildTarget( const Reference< XComponentContext >& xContext )
407 : {
408 0 : ConfigData configData = init( xContext );
409 :
410 0 : if( configData.locale.isEmpty() || configData.system.isEmpty() )
411 0 : return;
412 :
413 0 : sal_uInt64 ret,len = 0;
414 0 : int j = configData.vFileURL.size();
415 :
416 0 : TVDom tvDom;
417 0 : TVDom* pTVDom = &tvDom;
418 :
419 0 : while( j )
420 : {
421 0 : len = configData.vFileLen[--j];
422 0 : char* s = new char[ int(len) ]; // the buffer to hold the installed files
423 0 : osl::File aFile( configData.vFileURL[j] );
424 0 : aFile.open( osl_File_OpenFlag_Read );
425 0 : aFile.read( s,len,ret );
426 0 : aFile.close();
427 :
428 0 : XML_Parser parser = XML_ParserCreate( 0 );
429 : XML_SetElementHandler( parser,
430 : start_handler,
431 0 : end_handler );
432 : XML_SetCharacterDataHandler( parser,
433 0 : data_handler);
434 0 : XML_SetUserData( parser,&pTVDom ); // does not return this
435 :
436 0 : XML_Status const parsed = XML_Parse(parser, s, int(len), j==0);
437 : SAL_WARN_IF(XML_STATUS_ERROR == parsed, "xmlhelp",
438 : "TVChildTarget::TVChildTarget(): Tree file parsing failed");
439 :
440 0 : XML_ParserFree( parser );
441 0 : delete[] s;
442 :
443 0 : Check(pTVDom);
444 0 : }
445 : // now TVDom holds the relevant information
446 :
447 0 : Elements.resize( tvDom.children.size() );
448 0 : for( size_t i = 0; i < Elements.size(); ++i )
449 0 : Elements[i] = new TVRead( configData,tvDom.children[i] );
450 : }
451 :
452 0 : TVChildTarget::~TVChildTarget()
453 : {
454 0 : }
455 :
456 0 : void TVChildTarget::Check(TVDom* tvDom)
457 : {
458 0 : if (tvDom->children.empty())
459 : {
460 0 : return;
461 : }
462 :
463 0 : unsigned i = 0;
464 0 : bool h = false;
465 :
466 0 : while((i<tvDom->children.size()-1) && (!h))
467 : {
468 0 : if (((tvDom->children[i])->application == (tvDom->children[tvDom->children.size()-1])->application) &&
469 0 : ((tvDom->children[i])->id == (tvDom->children[tvDom->children.size()-1])->id))
470 : {
471 0 : TVDom* p = tvDom->children[tvDom->children.size()-1];
472 :
473 0 : for(size_t k=0; k<p->children.size(); ++k)
474 0 : if (!SearchAndInsert(p->children[k], tvDom->children[i])) tvDom->children[i]->newChild(p->children[k]);
475 :
476 0 : tvDom->children.pop_back();
477 0 : h = true;
478 : }
479 0 : ++i;
480 : }
481 : }
482 :
483 0 : bool TVChildTarget::SearchAndInsert(TVDom* p, TVDom* tvDom)
484 : {
485 0 : if (p->isLeaf()) return false;
486 :
487 0 : bool h = false;
488 0 : sal_Int32 max = 0;
489 :
490 0 : std::vector< TVDom* >::iterator max_It, i;
491 0 : max_It = tvDom->children.begin();
492 :
493 : sal_Int32 c_int;
494 0 : sal_Int32 p_int = p->id.toInt32();
495 :
496 0 : for(i = tvDom->children.begin(); i!=tvDom->children.end(); ++i)
497 0 : if (!((*i)->isLeaf()) &&
498 0 : ((*i)->id.getLength() == p->id.getLength()) &&
499 0 : (p->id.replaceAt((*i)->parent->id.getLength(), p->id.getLength()-(*i)->parent->id.getLength(), OUString("")) == (*i)->parent->id)) //prefix check
500 : {
501 0 : h = true;
502 0 : c_int = (*i)->id.toInt32();
503 :
504 0 : if (p_int==c_int)
505 : {
506 0 : (*(tvDom->children.insert(i+1, p)))->parent = tvDom;
507 0 : return true;
508 : }
509 0 : else if(c_int>max && c_int < p_int)
510 : {
511 0 : max = c_int;
512 0 : max_It = i+1;
513 : }
514 : }
515 0 : if (h) (*(tvDom->children.insert(max_It, p)))->parent = tvDom;
516 : else
517 : {
518 0 : i = tvDom->children.begin();
519 0 : while ((i!=tvDom->children.end()) && (!h))
520 : {
521 0 : h = SearchAndInsert(p, *i);
522 0 : ++i;
523 : }
524 : }
525 0 : return h;
526 : }
527 :
528 : Any SAL_CALL
529 0 : TVChildTarget::getByName( const OUString& aName )
530 : throw( NoSuchElementException,
531 : WrappedTargetException,
532 : RuntimeException, std::exception )
533 : {
534 0 : OUString num( aName.getStr()+2,aName.getLength()-4 );
535 0 : sal_Int32 idx = num.toInt32() - 1;
536 0 : if( idx < 0 || Elements.size() <= sal_uInt32( idx ) )
537 0 : throw NoSuchElementException();
538 :
539 0 : Any aAny;
540 0 : cppu::OWeakObject* p = Elements[idx].get();
541 0 : aAny <<= Reference< XInterface >( p );
542 0 : return aAny;
543 : }
544 :
545 : Sequence< OUString > SAL_CALL
546 0 : TVChildTarget::getElementNames( )
547 : throw( RuntimeException, std::exception )
548 : {
549 0 : Sequence< OUString > seq( Elements.size() );
550 0 : for( size_t i = 0; i < Elements.size(); ++i )
551 0 : seq[i] = OUString::number( 1+i );
552 :
553 0 : return seq;
554 : }
555 :
556 : sal_Bool SAL_CALL
557 0 : TVChildTarget::hasByName( const OUString& aName )
558 : throw( RuntimeException, std::exception )
559 : {
560 0 : OUString num( aName.getStr()+2,aName.getLength()-4 );
561 0 : sal_Int32 idx = num.toInt32() - 1;
562 0 : if( idx < 0 || Elements.size() <= sal_uInt32( idx ) )
563 0 : return false;
564 :
565 0 : return true;
566 : }
567 :
568 : // XHierarchicalNameAccess
569 :
570 : Any SAL_CALL
571 0 : TVChildTarget::getByHierarchicalName( const OUString& aName )
572 : throw( NoSuchElementException,
573 : RuntimeException, std::exception )
574 : {
575 : sal_Int32 idx;
576 0 : OUString name( aName );
577 :
578 0 : if( ( idx = name.indexOf( '/' ) ) != -1 )
579 : {
580 0 : OUString num( name.getStr()+2,idx-4 );
581 0 : sal_Int32 pref = num.toInt32() - 1;
582 :
583 0 : if( pref < 0 || Elements.size() <= sal_uInt32( pref ) )
584 0 : throw NoSuchElementException();
585 :
586 0 : return Elements[pref]->getByHierarchicalName( name.copy( 1 + idx ) );
587 : }
588 : else
589 0 : return getByName( name );
590 : }
591 :
592 : sal_Bool SAL_CALL
593 0 : TVChildTarget::hasByHierarchicalName( const OUString& aName )
594 : throw( RuntimeException, std::exception )
595 : {
596 : sal_Int32 idx;
597 0 : OUString name( aName );
598 :
599 0 : if( ( idx = name.indexOf( '/' ) ) != -1 )
600 : {
601 0 : OUString num( name.getStr()+2,idx-4 );
602 0 : sal_Int32 pref = num.toInt32() - 1;
603 0 : if( pref < 0 || Elements.size() <= sal_uInt32( pref ) )
604 0 : return false;
605 :
606 0 : return Elements[pref]->hasByHierarchicalName( name.copy( 1 + idx ) );
607 : }
608 : else
609 0 : return hasByName( name );
610 : }
611 :
612 0 : ConfigData TVChildTarget::init( const Reference< XComponentContext >& xContext )
613 : {
614 0 : ConfigData configData;
615 0 : Reference< XMultiServiceFactory > sProvider( getConfiguration(xContext) );
616 :
617 : /**********************************************************************/
618 : /* reading Office.Common */
619 : /**********************************************************************/
620 :
621 : Reference< XHierarchicalNameAccess > xHierAccess( getHierAccess( sProvider,
622 0 : "org.openoffice.Office.Common" ) );
623 0 : OUString system( getKey( xHierAccess,"Help/System" ) );
624 0 : bool showBasic( getBooleanKey(xHierAccess,"Help/ShowBasic") );
625 0 : OUString instPath( getKey( xHierAccess,"Path/Current/Help" ) );
626 0 : if( instPath.isEmpty() )
627 : // try to determine path from default
628 0 : instPath = "$(instpath)/help";
629 :
630 : // replace anything like $(instpath);
631 0 : subst( instPath );
632 :
633 : /**********************************************************************/
634 : /* reading setup */
635 : /**********************************************************************/
636 :
637 0 : xHierAccess = getHierAccess( sProvider,
638 0 : "org.openoffice.Setup" );
639 :
640 0 : OUString setupversion( getKey( xHierAccess,"Product/ooSetupVersion" ) );
641 0 : OUString setupextension;
642 :
643 : try
644 : {
645 0 : Reference< lang::XMultiServiceFactory > xConfigProvider = theDefaultProvider::get( xContext );
646 :
647 0 : uno::Sequence < uno::Any > lParams(1);
648 0 : beans::PropertyValue aParam ;
649 0 : aParam.Name = "nodepath";
650 0 : aParam.Value <<= OUString("/org.openoffice.Setup/Product");
651 0 : lParams[0] = uno::makeAny(aParam);
652 :
653 : // open it
654 0 : uno::Reference< uno::XInterface > xCFG( xConfigProvider->createInstanceWithArguments(
655 : OUString("com.sun.star.configuration.ConfigurationAccess"),
656 0 : lParams) );
657 :
658 0 : uno::Reference< container::XNameAccess > xDirectAccess(xCFG, uno::UNO_QUERY);
659 0 : uno::Any aRet = xDirectAccess->getByName("ooSetupExtension");
660 :
661 0 : aRet >>= setupextension;
662 : }
663 0 : catch ( uno::Exception& )
664 : {
665 : }
666 :
667 0 : OUString productVersion( setupversion + " " + setupextension );
668 0 : OUString locale( getKey( xHierAccess,"L10N/ooLocale" ) );
669 :
670 : // Determine fileurl from url and locale
671 0 : OUString url;
672 0 : osl::FileBase::RC errFile = osl::FileBase::getFileURLFromSystemPath( instPath,url );
673 0 : if( errFile != osl::FileBase::E_None ) return configData;
674 0 : if( !url.endsWith("/") )
675 0 : url += "/";
676 0 : OUString ret;
677 : sal_Int32 idx;
678 0 : osl::DirectoryItem aDirItem;
679 0 : if( osl::FileBase::E_None == osl::DirectoryItem::get( url + locale,aDirItem ) )
680 0 : ret = locale;
681 0 : else if( ( ( idx = locale.indexOf( '-' ) ) != -1 ||
682 0 : ( idx = locale.indexOf( '_' ) ) != -1 ) &&
683 0 : osl::FileBase::E_None == osl::DirectoryItem::get( url + locale.copy( 0,idx ),
684 0 : aDirItem ) )
685 0 : ret = locale.copy( 0,idx );
686 : else
687 : {
688 0 : locale = "en-US";
689 0 : ret = "en";
690 : }
691 0 : url = url + ret;
692 :
693 : // first of all, try do determine whether there are any *.tree files present
694 :
695 : // Start with extensions to set them at the end of the list
696 0 : TreeFileIterator aTreeIt( locale );
697 0 : OUString aTreeFile;
698 : sal_Int32 nFileSize;
699 0 : while( !(aTreeFile = aTreeIt.nextTreeFile( nFileSize ) ).isEmpty() )
700 : {
701 0 : configData.vFileLen.push_back( nFileSize );
702 0 : configData.vFileURL.push_back( aTreeFile );
703 : }
704 :
705 0 : osl::Directory aDirectory( url );
706 : osl::FileStatus aFileStatus(
707 0 : osl_FileStatus_Mask_FileName | osl_FileStatus_Mask_FileURL );
708 0 : if( osl::Directory::E_None == aDirectory.open() )
709 : {
710 0 : OUString aFileUrl, aFileName;
711 0 : while( aDirectory.getNextItem( aDirItem ) == osl::FileBase::E_None &&
712 0 : aDirItem.getFileStatus( aFileStatus ) == osl::FileBase::E_None &&
713 0 : aFileStatus.isValid( osl_FileStatus_Mask_FileURL ) &&
714 0 : aFileStatus.isValid( osl_FileStatus_Mask_FileName ) )
715 : {
716 0 : aFileUrl = aFileStatus.getFileURL();
717 0 : aFileName = aFileStatus.getFileName();
718 0 : int idx_ = aFileName.lastIndexOf( '.' );
719 0 : if( idx_ == -1 )
720 0 : continue;
721 :
722 0 : const sal_Unicode* str = aFileName.getStr();
723 :
724 0 : if( aFileName.getLength() == idx_ + 5 &&
725 0 : ( str[idx_ + 1] == 't' || str[idx_ + 1] == 'T' ) &&
726 0 : ( str[idx_ + 2] == 'r' || str[idx_ + 2] == 'R' ) &&
727 0 : ( str[idx_ + 3] == 'e' || str[idx_ + 3] == 'E' ) &&
728 0 : ( str[idx_ + 4] == 'e' || str[idx_ + 4] == 'E' ) )
729 : {
730 0 : OUString baseName = aFileName.copy(0,idx_).toAsciiLowerCase();
731 0 : if(! showBasic && baseName == "sbasic" )
732 0 : continue;
733 0 : osl::File aFile( aFileUrl );
734 0 : if( osl::FileBase::E_None == aFile.open( osl_File_OpenFlag_Read ) )
735 : {
736 : // use the file size, not aFileStatus size, in case the
737 : // tree file is a symlink
738 : sal_uInt64 nSize;
739 0 : aFile.getSize( nSize );
740 0 : configData.vFileLen.push_back( nSize );
741 0 : configData.vFileURL.push_back( aFileUrl );
742 0 : aFile.close();
743 0 : }
744 : }
745 : }
746 0 : aDirectory.close();
747 : }
748 :
749 0 : configData.m_vAdd[0] = 12;
750 0 : configData.m_vAdd[1] = 15;
751 0 : configData.m_vAdd[2] = 11;
752 0 : configData.m_vAdd[3] = 14;
753 0 : configData.m_vAdd[4] = 12;
754 0 : configData.m_vReplacement[0] = utl::ConfigManager::getProductName();
755 0 : configData.m_vReplacement[1] = productVersion;
756 : // m_vReplacement[2...4] (vendorName/-Version/-Short) are empty strings
757 :
758 0 : configData.system = system;
759 0 : configData.locale = locale;
760 0 : configData.appendix =
761 0 : "?Language=" +
762 0 : configData.locale +
763 0 : "&System=" +
764 0 : configData.system +
765 0 : "&UseDB=no";
766 :
767 0 : return configData;
768 : }
769 :
770 : Reference< XMultiServiceFactory >
771 0 : TVChildTarget::getConfiguration(const Reference< XComponentContext >& rxContext)
772 : {
773 0 : Reference< XMultiServiceFactory > xProvider;
774 0 : if( rxContext.is() )
775 : {
776 : try
777 : {
778 0 : xProvider = theDefaultProvider::get( rxContext );
779 : }
780 0 : catch( const com::sun::star::uno::Exception& )
781 : {
782 : OSL_ENSURE( xProvider.is(),"can not instantiate configuration" );
783 : }
784 : }
785 :
786 0 : return xProvider;
787 : }
788 :
789 : Reference< XHierarchicalNameAccess >
790 0 : TVChildTarget::getHierAccess( const Reference< XMultiServiceFactory >& sProvider,
791 : const char* file )
792 : {
793 0 : Reference< XHierarchicalNameAccess > xHierAccess;
794 :
795 0 : if( sProvider.is() )
796 : {
797 0 : Sequence< Any > seq(1);
798 : OUString sReaderService =
799 0 : OUString( "com.sun.star.configuration.ConfigurationAccess" );
800 :
801 0 : seq[0] <<= OUString::createFromAscii( file );
802 :
803 : try
804 : {
805 0 : xHierAccess =
806 : Reference< XHierarchicalNameAccess >
807 0 : ( sProvider->createInstanceWithArguments( sReaderService,seq ),
808 0 : UNO_QUERY );
809 : }
810 0 : catch( const com::sun::star::uno::Exception& )
811 : {
812 0 : }
813 : }
814 :
815 0 : return xHierAccess;
816 : }
817 :
818 : OUString
819 0 : TVChildTarget::getKey( const Reference< XHierarchicalNameAccess >& xHierAccess,
820 : const char* key )
821 : {
822 0 : OUString instPath;
823 0 : if( xHierAccess.is() )
824 : {
825 0 : Any aAny;
826 : try
827 : {
828 0 : aAny =
829 0 : xHierAccess->getByHierarchicalName( OUString::createFromAscii( key ) );
830 : }
831 0 : catch( const com::sun::star::container::NoSuchElementException& )
832 : {
833 : }
834 0 : aAny >>= instPath;
835 : }
836 0 : return instPath;
837 : }
838 :
839 : bool
840 0 : TVChildTarget::getBooleanKey(const Reference<
841 : XHierarchicalNameAccess >& xHierAccess,
842 : const char* key)
843 : {
844 0 : bool ret = false;
845 0 : if( xHierAccess.is() )
846 : {
847 0 : Any aAny;
848 : try
849 : {
850 0 : aAny =
851 0 : xHierAccess->getByHierarchicalName(
852 0 : OUString::createFromAscii(key));
853 : }
854 0 : catch( const com::sun::star::container::NoSuchElementException& )
855 : {
856 : }
857 0 : aAny >>= ret;
858 : }
859 0 : return ret;
860 : }
861 :
862 0 : void TVChildTarget::subst( OUString& instpath )
863 : {
864 0 : SvtPathOptions aOptions;
865 0 : instpath = aOptions.SubstituteVariable( instpath );
866 0 : }
867 :
868 : // class ExtensionIteratorBase
869 :
870 : static const char aHelpMediaType[] = "application/vnd.sun.star.help";
871 :
872 0 : ExtensionIteratorBase::ExtensionIteratorBase( const OUString& aLanguage )
873 : : m_eState( USER_EXTENSIONS )
874 0 : , m_aLanguage( aLanguage )
875 : {
876 0 : init();
877 0 : }
878 :
879 0 : void ExtensionIteratorBase::init()
880 : {
881 0 : m_xContext = ::comphelper::getProcessComponentContext();
882 0 : if( !m_xContext.is() )
883 : {
884 0 : throw RuntimeException( "ExtensionIteratorBase::init(), no XComponentContext" );
885 : }
886 :
887 0 : m_xSFA = ucb::SimpleFileAccess::create(m_xContext);
888 :
889 0 : m_bUserPackagesLoaded = false;
890 0 : m_bSharedPackagesLoaded = false;
891 0 : m_bBundledPackagesLoaded = false;
892 0 : m_iUserPackage = 0;
893 0 : m_iSharedPackage = 0;
894 0 : m_iBundledPackage = 0;
895 0 : }
896 :
897 0 : Reference< deployment::XPackage > ExtensionIteratorBase::implGetHelpPackageFromPackage
898 : ( Reference< deployment::XPackage > xPackage, Reference< deployment::XPackage >& o_xParentPackageBundle )
899 : {
900 0 : o_xParentPackageBundle.clear();
901 :
902 0 : Reference< deployment::XPackage > xHelpPackage;
903 0 : if( !xPackage.is() )
904 0 : return xHelpPackage;
905 :
906 : // Check if parent package is registered
907 0 : beans::Optional< beans::Ambiguous<sal_Bool> > option( xPackage->isRegistered
908 0 : ( Reference<task::XAbortChannel>(), Reference<ucb::XCommandEnvironment>() ) );
909 0 : bool bRegistered = false;
910 0 : if( option.IsPresent )
911 : {
912 0 : beans::Ambiguous<sal_Bool> const & reg = option.Value;
913 0 : if( !reg.IsAmbiguous && reg.Value )
914 0 : bRegistered = true;
915 : }
916 0 : if( !bRegistered )
917 0 : return xHelpPackage;
918 :
919 0 : if( xPackage->isBundle() )
920 : {
921 0 : Sequence< Reference< deployment::XPackage > > aPkgSeq = xPackage->getBundle
922 0 : ( Reference<task::XAbortChannel>(), Reference<ucb::XCommandEnvironment>() );
923 0 : sal_Int32 nPkgCount = aPkgSeq.getLength();
924 0 : const Reference< deployment::XPackage >* pSeq = aPkgSeq.getConstArray();
925 0 : for( sal_Int32 iPkg = 0 ; iPkg < nPkgCount ; ++iPkg )
926 : {
927 0 : const Reference< deployment::XPackage > xSubPkg = pSeq[ iPkg ];
928 0 : const Reference< deployment::XPackageTypeInfo > xPackageTypeInfo = xSubPkg->getPackageType();
929 0 : OUString aMediaType = xPackageTypeInfo->getMediaType();
930 0 : if( aMediaType == aHelpMediaType )
931 : {
932 0 : xHelpPackage = xSubPkg;
933 0 : o_xParentPackageBundle = xPackage;
934 0 : break;
935 : }
936 0 : }
937 : }
938 : else
939 : {
940 0 : const Reference< deployment::XPackageTypeInfo > xPackageTypeInfo = xPackage->getPackageType();
941 0 : OUString aMediaType = xPackageTypeInfo->getMediaType();
942 0 : if( aMediaType == aHelpMediaType )
943 0 : xHelpPackage = xPackage;
944 : }
945 :
946 0 : return xHelpPackage;
947 : }
948 :
949 0 : Reference< deployment::XPackage > ExtensionIteratorBase::implGetNextUserHelpPackage
950 : ( Reference< deployment::XPackage >& o_xParentPackageBundle )
951 : {
952 0 : Reference< deployment::XPackage > xHelpPackage;
953 :
954 0 : if( !m_bUserPackagesLoaded )
955 : {
956 : Reference< XPackageManager > xUserManager =
957 0 : thePackageManagerFactory::get( m_xContext )->getPackageManager("user");
958 0 : m_aUserPackagesSeq = xUserManager->getDeployedPackages
959 0 : ( Reference< task::XAbortChannel >(), Reference< ucb::XCommandEnvironment >() );
960 :
961 0 : m_bUserPackagesLoaded = true;
962 : }
963 :
964 0 : if( m_iUserPackage == m_aUserPackagesSeq.getLength() )
965 : {
966 0 : m_eState = SHARED_EXTENSIONS; // Later: SHARED_MODULE
967 : }
968 : else
969 : {
970 0 : const Reference< deployment::XPackage >* pUserPackages = m_aUserPackagesSeq.getConstArray();
971 0 : Reference< deployment::XPackage > xPackage = pUserPackages[ m_iUserPackage++ ];
972 : OSL_ENSURE( xPackage.is(), "ExtensionIteratorBase::implGetNextUserHelpPackage(): Invalid package" );
973 0 : xHelpPackage = implGetHelpPackageFromPackage( xPackage, o_xParentPackageBundle );
974 : }
975 :
976 0 : return xHelpPackage;
977 : }
978 :
979 0 : Reference< deployment::XPackage > ExtensionIteratorBase::implGetNextSharedHelpPackage
980 : ( Reference< deployment::XPackage >& o_xParentPackageBundle )
981 : {
982 0 : Reference< deployment::XPackage > xHelpPackage;
983 :
984 0 : if( !m_bSharedPackagesLoaded )
985 : {
986 : Reference< XPackageManager > xSharedManager =
987 0 : thePackageManagerFactory::get( m_xContext )->getPackageManager("shared");
988 0 : m_aSharedPackagesSeq = xSharedManager->getDeployedPackages
989 0 : ( Reference< task::XAbortChannel >(), Reference< ucb::XCommandEnvironment >() );
990 :
991 0 : m_bSharedPackagesLoaded = true;
992 : }
993 :
994 0 : if( m_iSharedPackage == m_aSharedPackagesSeq.getLength() )
995 : {
996 0 : m_eState = BUNDLED_EXTENSIONS;
997 : }
998 : else
999 : {
1000 0 : const Reference< deployment::XPackage >* pSharedPackages = m_aSharedPackagesSeq.getConstArray();
1001 0 : Reference< deployment::XPackage > xPackage = pSharedPackages[ m_iSharedPackage++ ];
1002 : OSL_ENSURE( xPackage.is(), "ExtensionIteratorBase::implGetNextSharedHelpPackage(): Invalid package" );
1003 0 : xHelpPackage = implGetHelpPackageFromPackage( xPackage, o_xParentPackageBundle );
1004 : }
1005 :
1006 0 : return xHelpPackage;
1007 : }
1008 :
1009 0 : Reference< deployment::XPackage > ExtensionIteratorBase::implGetNextBundledHelpPackage
1010 : ( Reference< deployment::XPackage >& o_xParentPackageBundle )
1011 : {
1012 0 : Reference< deployment::XPackage > xHelpPackage;
1013 :
1014 0 : if( !m_bBundledPackagesLoaded )
1015 : {
1016 : Reference< XPackageManager > xBundledManager =
1017 0 : thePackageManagerFactory::get( m_xContext )->getPackageManager("bundled");
1018 0 : m_aBundledPackagesSeq = xBundledManager->getDeployedPackages
1019 0 : ( Reference< task::XAbortChannel >(), Reference< ucb::XCommandEnvironment >() );
1020 :
1021 0 : m_bBundledPackagesLoaded = true;
1022 : }
1023 :
1024 0 : if( m_iBundledPackage == m_aBundledPackagesSeq.getLength() )
1025 : {
1026 0 : m_eState = END_REACHED;
1027 : }
1028 : else
1029 : {
1030 0 : const Reference< deployment::XPackage >* pBundledPackages = m_aBundledPackagesSeq.getConstArray();
1031 0 : Reference< deployment::XPackage > xPackage = pBundledPackages[ m_iBundledPackage++ ];
1032 : OSL_ENSURE( xPackage.is(), "ExtensionIteratorBase::implGetNextBundledHelpPackage(): Invalid package" );
1033 0 : xHelpPackage = implGetHelpPackageFromPackage( xPackage, o_xParentPackageBundle );
1034 : }
1035 :
1036 0 : return xHelpPackage;
1037 : }
1038 :
1039 0 : inline bool isLetter( sal_Unicode c )
1040 : {
1041 0 : return comphelper::string::isalphaAscii(c);
1042 : }
1043 :
1044 0 : void ExtensionIteratorBase::implGetLanguageVectorFromPackage( ::std::vector< OUString > &rv,
1045 : com::sun::star::uno::Reference< com::sun::star::deployment::XPackage > xPackage )
1046 : {
1047 0 : rv.clear();
1048 0 : OUString aExtensionPath = xPackage->getURL();
1049 0 : Sequence< OUString > aEntrySeq = m_xSFA->getFolderContents( aExtensionPath, true );
1050 :
1051 0 : const OUString* pSeq = aEntrySeq.getConstArray();
1052 0 : sal_Int32 nCount = aEntrySeq.getLength();
1053 0 : for( sal_Int32 i = 0 ; i < nCount ; ++i )
1054 : {
1055 0 : OUString aEntry = pSeq[i];
1056 0 : if( m_xSFA->isFolder( aEntry ) )
1057 : {
1058 0 : sal_Int32 nLastSlash = aEntry.lastIndexOf( '/' );
1059 0 : if( nLastSlash != -1 )
1060 : {
1061 0 : OUString aPureEntry = aEntry.copy( nLastSlash + 1 );
1062 :
1063 : // Check language sceme
1064 0 : int nLen = aPureEntry.getLength();
1065 0 : const sal_Unicode* pc = aPureEntry.getStr();
1066 0 : bool bStartCanBeLanguage = ( nLen >= 2 && isLetter( pc[0] ) && isLetter( pc[1] ) );
1067 0 : bool bIsLanguage = bStartCanBeLanguage &&
1068 0 : ( nLen == 2 || (nLen == 5 && pc[2] == '-' && isLetter( pc[3] ) && isLetter( pc[4] )) );
1069 0 : if( bIsLanguage )
1070 0 : rv.push_back( aPureEntry );
1071 : }
1072 : }
1073 0 : }
1074 0 : }
1075 :
1076 : // class TreeFileIterator
1077 :
1078 0 : OUString TreeFileIterator::nextTreeFile( sal_Int32& rnFileSize )
1079 : {
1080 0 : OUString aRetFile;
1081 :
1082 0 : while( aRetFile.isEmpty() && m_eState != END_REACHED )
1083 : {
1084 0 : switch( m_eState )
1085 : {
1086 : case USER_EXTENSIONS:
1087 : {
1088 0 : Reference< deployment::XPackage > xParentPackageBundle;
1089 0 : Reference< deployment::XPackage > xHelpPackage = implGetNextUserHelpPackage( xParentPackageBundle );
1090 0 : if( !xHelpPackage.is() )
1091 0 : break;
1092 :
1093 0 : aRetFile = implGetTreeFileFromPackage( rnFileSize, xHelpPackage );
1094 0 : break;
1095 : }
1096 :
1097 : case SHARED_EXTENSIONS:
1098 : {
1099 0 : Reference< deployment::XPackage > xParentPackageBundle;
1100 0 : Reference< deployment::XPackage > xHelpPackage = implGetNextSharedHelpPackage( xParentPackageBundle );
1101 0 : if( !xHelpPackage.is() )
1102 0 : break;
1103 :
1104 0 : aRetFile = implGetTreeFileFromPackage( rnFileSize, xHelpPackage );
1105 0 : break;
1106 : }
1107 : case BUNDLED_EXTENSIONS:
1108 : {
1109 0 : Reference< deployment::XPackage > xParentPackageBundle;
1110 0 : Reference< deployment::XPackage > xHelpPackage = implGetNextBundledHelpPackage( xParentPackageBundle );
1111 0 : if( !xHelpPackage.is() )
1112 0 : break;
1113 :
1114 0 : aRetFile = implGetTreeFileFromPackage( rnFileSize, xHelpPackage );
1115 0 : break;
1116 : }
1117 :
1118 : case END_REACHED:
1119 : OSL_FAIL( "DataBaseIterator::nextTreeFile(): Invalid case END_REACHED" );
1120 0 : break;
1121 : }
1122 : }
1123 :
1124 0 : return aRetFile;
1125 : }
1126 :
1127 0 : OUString TreeFileIterator::expandURL( const OUString& aURL )
1128 : {
1129 0 : static Reference< util::XMacroExpander > xMacroExpander;
1130 0 : static Reference< uri::XUriReferenceFactory > xFac;
1131 :
1132 0 : osl::MutexGuard aGuard( m_aMutex );
1133 :
1134 0 : if( !xMacroExpander.is() || !xFac.is() )
1135 : {
1136 0 : xFac = uri::UriReferenceFactory::create( m_xContext );
1137 :
1138 0 : xMacroExpander = util::theMacroExpander::get(m_xContext);
1139 : }
1140 :
1141 0 : OUString aRetURL = aURL;
1142 0 : Reference< uri::XUriReference > uriRef;
1143 : for (;;)
1144 : {
1145 0 : uriRef = Reference< uri::XUriReference >( xFac->parse( aRetURL ), UNO_QUERY );
1146 0 : if ( uriRef.is() )
1147 : {
1148 0 : Reference < uri::XVndSunStarExpandUrl > sxUri( uriRef, UNO_QUERY );
1149 0 : if( !sxUri.is() )
1150 0 : break;
1151 :
1152 0 : aRetURL = sxUri->expand( xMacroExpander );
1153 : }
1154 0 : }
1155 0 : return aRetURL;
1156 : }
1157 :
1158 0 : OUString TreeFileIterator::implGetTreeFileFromPackage
1159 : ( sal_Int32& rnFileSize, Reference< deployment::XPackage > xPackage )
1160 : {
1161 0 : OUString aRetFile;
1162 0 : OUString aLanguage = m_aLanguage;
1163 0 : for( sal_Int32 iPass = 0 ; iPass < 2 ; ++iPass )
1164 : {
1165 0 : aRetFile = expandURL( xPackage->getURL() + "/" + aLanguage + "/help.tree" );
1166 0 : if( iPass == 0 )
1167 : {
1168 0 : if( m_xSFA->exists( aRetFile ) )
1169 0 : break;
1170 :
1171 0 : ::std::vector< OUString > av;
1172 0 : implGetLanguageVectorFromPackage( av, xPackage );
1173 0 : ::std::vector< OUString >::const_iterator pFound = LanguageTag::getFallback( av, m_aLanguage );
1174 0 : if( pFound != av.end() )
1175 0 : aLanguage = *pFound;
1176 : }
1177 : }
1178 :
1179 0 : rnFileSize = 0;
1180 0 : if( m_xSFA->exists( aRetFile ) )
1181 0 : rnFileSize = m_xSFA->getSize( aRetFile );
1182 : else
1183 0 : aRetFile.clear();
1184 :
1185 0 : return aRetFile;
1186 : }
1187 :
1188 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|