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