1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_ucb.hxx"
26 
27 /**************************************************************************
28 								TODO
29  **************************************************************************
30 
31  - HierarchyEntry::move
32    --> Rewrite to use XNamed ( once this is supported by config db api ).
33 
34  *************************************************************************/
35 #include "hierarchydata.hxx"
36 
37 #include <vector>
38 #include <osl/diagnose.h>
39 #include <rtl/ustrbuf.hxx>
40 #include <com/sun/star/beans/PropertyValue.hpp>
41 #include <com/sun/star/container/XHierarchicalNameAccess.hpp>
42 #include <com/sun/star/container/XNameContainer.hpp>
43 #include <com/sun/star/container/XNameReplace.hpp>
44 #include <com/sun/star/util/XChangesBatch.hpp>
45 #ifndef _COM_SUN_STAR_UTIL_XOFFICEINSTALLTIONDIRECTORIES_HPP_
46 #include <com/sun/star/util/XOfficeInstallationDirectories.hpp>
47 #endif
48 #include "hierarchyprovider.hxx"
49 #include "hierarchyuri.hxx"
50 
51 using namespace com::sun::star;
52 
53 namespace hierarchy_ucp
54 {
55 
56 //=========================================================================
57 struct HierarchyEntry::iterator_Impl
58 {
59     HierarchyEntryData                                     entry;
60     uno::Reference< container::XHierarchicalNameAccess >   dir;
61     uno::Reference< util::XOfficeInstallationDirectories > officeDirs;
62     uno::Sequence< rtl::OUString>                          names;
63     sal_Int32                                              pos;
iterator_Implhierarchy_ucp::HierarchyEntry::iterator_Impl64     iterator_Impl()
65     : officeDirs( 0 ), pos( -1 /* before first */ ) {};
66 };
67 
68 //=========================================================================
makeXMLName(const rtl::OUString & rIn,rtl::OUStringBuffer & rBuffer)69 void makeXMLName( const rtl::OUString & rIn, rtl::OUStringBuffer & rBuffer  )
70 {
71     sal_Int32 nCount = rIn.getLength();
72     for ( sal_Int32 n = 0; n < nCount; ++n )
73     {
74         const sal_Unicode c = rIn.getStr()[ n ];
75         switch ( c )
76         {
77             case '&':
78                 rBuffer.appendAscii( "&amp;" );
79                 break;
80 
81             case '"':
82                 rBuffer.appendAscii( "&quot;" );
83                 break;
84 
85             case '\'':
86                 rBuffer.appendAscii( "&apos;" );
87                 break;
88 
89             case '<':
90                 rBuffer.appendAscii( "&lt;" );
91                 break;
92 
93             case '>':
94                 rBuffer.appendAscii( "&gt;" );
95                 break;
96 
97             default:
98                 rBuffer.append( c );
99                 break;
100         }
101     }
102 }
103 
104 //=========================================================================
105 //=========================================================================
106 //
107 // HierarchyEntry Implementation.
108 //
109 //=========================================================================
110 //=========================================================================
111 
112 #define READ_SERVICE_NAME      "com.sun.star.ucb.HierarchyDataReadAccess"
113 #define READWRITE_SERVICE_NAME "com.sun.star.ucb.HierarchyDataReadWriteAccess"
114 
115 // describe path of cfg entry
116 #define	CFGPROPERTY_NODEPATH	"nodepath"
117 
118 //=========================================================================
HierarchyEntry(const uno::Reference<lang::XMultiServiceFactory> & rSMgr,HierarchyContentProvider * pProvider,const rtl::OUString & rURL)119 HierarchyEntry::HierarchyEntry(
120 				const uno::Reference< lang::XMultiServiceFactory >& rSMgr,
121 				HierarchyContentProvider* pProvider,
122 				const rtl::OUString& rURL )
123 : m_xSMgr( rSMgr ),
124   m_xOfficeInstDirs( pProvider->getOfficeInstallationDirectories() ),
125   m_bTriedToGetRootReadAccess( sal_False )
126 {
127     HierarchyUri aUri( rURL );
128     m_aServiceSpecifier = aUri.getService();
129 
130 	if ( pProvider )
131 	{
132         m_xConfigProvider
133             = pProvider->getConfigProvider( m_aServiceSpecifier );
134         m_xRootReadAccess
135             = pProvider->getRootConfigReadNameAccess( m_aServiceSpecifier );
136 	}
137 
138 	// Note: do not init m_aPath in init list. createPathFromHierarchyURL
139 	//       needs m_xSMgr and m_aMutex.
140     m_aPath = createPathFromHierarchyURL( aUri );
141 
142 	// Extract language independent name from URL.
143 	sal_Int32 nPos = rURL.lastIndexOf( '/' );
144 	if ( nPos > HIERARCHY_URL_SCHEME_LENGTH )
145 		m_aName = rURL.copy( nPos + 1 );
146 	else
147         OSL_ENSURE( sal_False, "HierarchyEntry - Invalid URL!" );
148 }
149 
150 //=========================================================================
hasData()151 sal_Bool HierarchyEntry::hasData()
152 {
153 	osl::Guard< osl::Mutex > aGuard( m_aMutex );
154 	uno::Reference< container::XHierarchicalNameAccess > xRootReadAccess
155         = getRootReadAccess();
156 
157     OSL_ENSURE( xRootReadAccess.is(), "HierarchyEntry::hasData - No root!" );
158 
159 	if ( xRootReadAccess.is() )
160 		return xRootReadAccess->hasByHierarchicalName( m_aPath );
161 
162 	return sal_False;
163 }
164 
165 //=========================================================================
getData(HierarchyEntryData & rData)166 sal_Bool HierarchyEntry::getData( HierarchyEntryData& rData )
167 {
168 	try
169 	{
170 		osl::Guard< osl::Mutex > aGuard( m_aMutex );
171 
172 		uno::Reference< container::XHierarchicalNameAccess > xRootReadAccess
173 			= getRootReadAccess();
174 
175         OSL_ENSURE( xRootReadAccess.is(),
176 					"HierarchyEntry::getData - No root!" );
177 
178 		if ( xRootReadAccess.is() )
179 		{
180 			rtl::OUString aTitlePath = m_aPath;
181 			aTitlePath += rtl::OUString::createFromAscii( "/Title" );
182 
183 			// Note: Avoid NoSuchElementExceptions, because exceptions are
184 			//       relatively 'expensive'. Checking for availability of
185 			//       title value is sufficient here, because if it is
186 			//       there, the other values will be available too.
187 			if ( !xRootReadAccess->hasByHierarchicalName( aTitlePath ) )
188 				return sal_False;
189 
190             rtl::OUString aValue;
191 
192 			// Get Title value.
193 			if ( !( xRootReadAccess->getByHierarchicalName( aTitlePath )
194                     >>= aValue ) )
195 			{
196                 OSL_ENSURE( sal_False,
197 							"HierarchyEntry::getData - "
198 							"Got no Title value!" );
199 				return sal_False;
200 			}
201 
202             rData.setTitle( aValue );
203 
204 			// Get TargetURL value.
205 			rtl::OUString aTargetURLPath = m_aPath;
206 			aTargetURLPath += rtl::OUString::createFromAscii( "/TargetURL" );
207 			if ( !( xRootReadAccess->getByHierarchicalName( aTargetURLPath )
208                     >>= aValue ) )
209 			{
210                 OSL_ENSURE( sal_False,
211 							"HierarchyEntry::getData - "
212 							"Got no TargetURL value!" );
213 				return sal_False;
214 			}
215 
216             // TargetURL property may contain a reference to the Office
217             // installation directory. To ensure a reloctable office
218             // installation, the path to the office installtion directory must
219             // never be stored directly. A placeholder is used instead. Replace
220             // it by actual installation directory.
221             if ( m_xOfficeInstDirs.is() && ( aValue.getLength() > 0 ) )
222                 aValue = m_xOfficeInstDirs->makeAbsoluteURL( aValue );
223             rData.setTargetURL( aValue );
224 
225             rtl::OUString aTypePath = m_aPath;
226             aTypePath += rtl::OUString::createFromAscii( "/Type" );
227             if ( xRootReadAccess->hasByHierarchicalName( aTypePath ) )
228             {
229                 // Might not be present since it was introduced long after
230                 // Title and TargetURL (#82433#)... So not getting it is
231                 // not an error.
232 
233                 // Get Type value.
234                 sal_Int32 nType = 0;
235                 if ( xRootReadAccess->getByHierarchicalName( aTypePath )
236                      >>= nType )
237                 {
238                     if ( nType == 0 )
239                     {
240                         rData.setType( HierarchyEntryData::LINK );
241                     }
242                     else if ( nType == 1 )
243                     {
244                         rData.setType( HierarchyEntryData::FOLDER );
245                     }
246                     else
247                     {
248                         OSL_ENSURE( sal_False,
249                                     "HierarchyEntry::getData - "
250                                     "Unknown Type value!" );
251                         return sal_False;
252                     }
253                 }
254             }
255 
256             rData.setName( m_aName );
257 			return sal_True;
258 		}
259 	}
260     catch ( uno::RuntimeException const & )
261 	{
262 		throw;
263 	}
264     catch ( container::NoSuchElementException const & )
265 	{
266 		// getByHierarchicalName
267 
268         OSL_ENSURE( sal_False,
269 					"HierarchyEntry::getData - caught NoSuchElementException!" );
270 	}
271 	return sal_False;
272 }
273 
274 //=========================================================================
setData(const HierarchyEntryData & rData,sal_Bool bCreate)275 sal_Bool HierarchyEntry::setData(
276 					const HierarchyEntryData& rData, sal_Bool bCreate )
277 {
278 	try
279 	{
280 		osl::Guard< osl::Mutex > aGuard( m_aMutex );
281 
282 		if ( !m_xConfigProvider.is() )
283 			m_xConfigProvider = uno::Reference< lang::XMultiServiceFactory >(
284                 m_xSMgr->createInstance( m_aServiceSpecifier ),
285 				uno::UNO_QUERY );
286 
287 		if ( m_xConfigProvider.is() )
288 		{
289 			// Create parent's key. It must exist!
290 
291             rtl::OUString aParentPath;
292 			sal_Bool bRoot = sal_True;
293 
294 			sal_Int32 nPos = m_aPath.lastIndexOf( '/' );
295 			if ( nPos != -1 )
296 			{
297 				// Skip "/Children" segment of the path, too.
298 				nPos = m_aPath.lastIndexOf( '/', nPos - 1 );
299 
300                 OSL_ENSURE( nPos != -1,
301 							"HierarchyEntry::setData - Wrong path!" );
302 
303 				aParentPath += m_aPath.copy( 0, nPos );
304 				bRoot = sal_False;
305 			}
306 
307             uno::Sequence< uno::Any > aArguments( 1 );
308 			beans::PropertyValue      aProperty;
309 
310 			aProperty.Name	  = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
311 													CFGPROPERTY_NODEPATH ) );
312 			aProperty.Value	<<= aParentPath;
313 			aArguments[ 0 ]	<<= aProperty;
314 
315 			uno::Reference< util::XChangesBatch > xBatch(
316 					m_xConfigProvider->createInstanceWithArguments(
317                         rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
318                             READWRITE_SERVICE_NAME ) ),
319 						aArguments ),
320 					uno::UNO_QUERY );
321 
322             OSL_ENSURE( xBatch.is(),
323 						"HierarchyEntry::setData - No batch!" );
324 
325 			uno::Reference< container::XNameAccess > xParentNameAccess(
326                 xBatch, uno::UNO_QUERY );
327 
328             OSL_ENSURE( xParentNameAccess.is(),
329 						"HierarchyEntry::setData - No name access!" );
330 
331 			if ( xBatch.is() && xParentNameAccess.is() )
332 			{
333 				// Try to create own key. It must not exist!
334 
335 				sal_Bool bExists = sal_True;
336 				uno::Any aMyKey;
337 
338 				try
339 				{
340 					uno::Reference< container::XNameAccess > xNameAccess;
341 
342 					if ( bRoot )
343 					{
344 						xNameAccess = xParentNameAccess;
345 					}
346 					else
347 					{
348 						xParentNameAccess->getByName(
349 							rtl::OUString::createFromAscii( "Children" ) )
350 								>>= xNameAccess;
351 					}
352 
353                     if ( xNameAccess->hasByName( m_aName ) )
354                         aMyKey = xNameAccess->getByName( m_aName );
355 					else
356 						bExists = sal_False;
357 				}
358 				catch ( container::NoSuchElementException const & )
359 				{
360 					bExists = sal_False;
361 				}
362 
363 				uno::Reference< container::XNameReplace >   xNameReplace;
364 				uno::Reference< container::XNameContainer > xContainer;
365 
366 				if ( bExists )
367 				{
368 					// Key exists. Replace values.
369 
370 					aMyKey >>= xNameReplace;
371 
372                     OSL_ENSURE( xNameReplace.is(),
373 								"HierarchyEntry::setData - No name replace!" );
374 				}
375 				else
376 				{
377 					if ( !bCreate )
378 						return sal_True;
379 
380 					// Key does not exist. Create / fill / insert it.
381 
382 					uno::Reference< lang::XSingleServiceFactory > xFac;
383 
384 					if ( bRoot )
385 					{
386 						// Special handling for children of root,
387 						// which is not an entry. It's only a set
388 						// of entries.
389 						xFac = uno::Reference< lang::XSingleServiceFactory >(
390                             xParentNameAccess, uno::UNO_QUERY );
391 					}
392 					else
393 					{
394 						// Append new entry to parents child list,
395 						// which is a set of entries.
396 						xParentNameAccess->getByName(
397 										rtl::OUString::createFromAscii(
398 											"Children" ) ) >>= xFac;
399 					}
400 
401                     OSL_ENSURE( xFac.is(),
402 								"HierarchyEntry::setData - No factory!" );
403 
404 					if ( xFac.is() )
405 					{
406 						xNameReplace
407                             = uno::Reference< container::XNameReplace >(
408                                 xFac->createInstance(), uno::UNO_QUERY );
409 
410                         OSL_ENSURE( xNameReplace.is(),
411 								"HierarchyEntry::setData - No name replace!" );
412 
413 						if ( xNameReplace.is() )
414 						{
415 							xContainer
416                                 = uno::Reference< container::XNameContainer >(
417                                     xFac, uno::UNO_QUERY );
418 
419                             OSL_ENSURE( xContainer.is(),
420 								"HierarchyEntry::setData - No container!" );
421 						}
422 					}
423 				}
424 
425 				if ( xNameReplace.is() )
426 				{
427 					// Set Title value.
428 					xNameReplace->replaceByName(
429                         rtl::OUString::createFromAscii( "Title" ),
430                         uno::makeAny( rData.getTitle() ) );
431 
432 					// Set TargetURL value.
433 
434                     // TargetURL property may contain a reference to the Office
435                     // installation directory. To ensure a reloctable office
436                     // installation, the path to the office installtion
437                     // directory must never be stored directly. Use a
438                     // placeholder instead.
439                     rtl::OUString aValue( rData.getTargetURL() );
440                     if ( m_xOfficeInstDirs.is() && ( aValue.getLength() > 0 ) )
441                         aValue
442                             = m_xOfficeInstDirs->makeRelocatableURL( aValue );
443 
444 					xNameReplace->replaceByName(
445                         rtl::OUString::createFromAscii( "TargetURL" ),
446                         uno::makeAny( aValue ) );
447 
448                     // Set Type value.
449                     sal_Int32 nType
450                         = rData.getType() == HierarchyEntryData::LINK ? 0 : 1;
451                     xNameReplace->replaceByName(
452                         rtl::OUString::createFromAscii( "Type" ),
453                         uno::makeAny( nType ) );
454 
455 					if ( xContainer.is() )
456 						xContainer->insertByName(
457                             m_aName, uno::makeAny( xNameReplace ) );
458 
459 					// Commit changes.
460 					xBatch->commitChanges();
461 					return sal_True;
462 				}
463 			}
464 		}
465 	}
466 	catch ( uno::RuntimeException const & )
467 	{
468 		throw;
469 	}
470 	catch ( lang::IllegalArgumentException const & )
471 	{
472 		// replaceByName, insertByName
473 
474         OSL_ENSURE(
475             sal_False,
476             "HierarchyEntry::setData - caught IllegalArgumentException!" );
477 	}
478 	catch ( container::NoSuchElementException const & )
479 	{
480 		// replaceByName, getByName
481 
482         OSL_ENSURE(
483             sal_False,
484             "HierarchyEntry::setData - caught NoSuchElementException!" );
485 	}
486 	catch ( container::ElementExistException const & )
487 	{
488 		// insertByName
489 
490         OSL_ENSURE(
491             sal_False,
492             "HierarchyEntry::setData - caught ElementExistException!" );
493 	}
494 	catch ( lang::WrappedTargetException const & )
495 	{
496 		// replaceByName, insertByName, getByName, commitChanges
497 
498         OSL_ENSURE(
499             sal_False,
500             "HierarchyEntry::setData - caught WrappedTargetException!" );
501 	}
502 	catch ( uno::Exception const & )
503 	{
504 		// createInstance, createInstanceWithArguments
505 
506         OSL_ENSURE(
507             sal_False,
508             "HierarchyEntry::setData - caught Exception!" );
509 	}
510 
511 	return sal_False;
512 }
513 
514 //=========================================================================
move(const rtl::OUString & rNewURL,const HierarchyEntryData & rData)515 sal_Bool HierarchyEntry::move(
516     const rtl::OUString& rNewURL, const HierarchyEntryData& rData )
517 {
518 	osl::Guard< osl::Mutex > aGuard( m_aMutex );
519 
520 	rtl::OUString aNewPath = createPathFromHierarchyURL( rNewURL );
521 
522 	if ( aNewPath == m_aPath )
523 		return sal_True;
524 
525 #if 0
526        // In the "near future"... ( not yet implemented in config db )
527 
528        - get update access for m_aPath
529        - update access -> XNamed
530        - xNamed::setName( newName )
531        - updateaccess commit
532 #else
533 
534 	sal_Bool bOldRoot = sal_True;
535 	uno::Reference< util::XChangesBatch > xOldParentBatch;
536 
537     rtl::OUString aNewKey;
538     sal_Int32 nURLPos = rNewURL.lastIndexOf( '/' );
539 	if ( nURLPos > HIERARCHY_URL_SCHEME_LENGTH )
540         aNewKey = rNewURL.copy( nURLPos + 1 );
541 	else
542     {
543         OSL_ENSURE( sal_False, "HierarchyEntry::move - Invalid URL!" );
544         return sal_False;
545     }
546 
547 	sal_Bool bNewRoot = sal_True;
548 	uno::Reference< util::XChangesBatch > xNewParentBatch;
549 
550 	sal_Bool bDifferentParents = sal_True;
551 
552 	try
553 	{
554 		if ( !m_xConfigProvider.is() )
555 			m_xConfigProvider = uno::Reference< lang::XMultiServiceFactory >(
556                 m_xSMgr->createInstance( m_aServiceSpecifier ),
557 				uno::UNO_QUERY );
558 
559 		if ( !m_xConfigProvider.is() )
560 			return sal_False;
561 
562         rtl::OUString aOldParentPath;
563 		sal_Int32 nPos = m_aPath.lastIndexOf( '/' );
564 		if ( nPos != -1 )
565 		{
566 			// Skip "/Children" segment of the path, too.
567 			nPos = m_aPath.lastIndexOf( '/', nPos - 1 );
568 
569             OSL_ENSURE( nPos != -1, "HierarchyEntry::move - Wrong path!" );
570 
571 			aOldParentPath += m_aPath.copy( 0, nPos );
572 			bOldRoot = sal_False;
573 		}
574 
575         rtl::OUString aNewParentPath;
576 		nPos = aNewPath.lastIndexOf( '/' );
577 		if ( nPos != -1 )
578 		{
579 			// Skip "/Children" segment of the path, too.
580 			nPos = aNewPath.lastIndexOf( '/', nPos - 1 );
581 
582             OSL_ENSURE( nPos != -1, "HierarchyEntry::move - Wrong path!" );
583 
584 			aNewParentPath += aNewPath.copy( 0, nPos );
585 			bNewRoot = sal_False;
586 		}
587 
588         uno::Sequence< uno::Any > aArguments( 1 );
589 		beans::PropertyValue	  aProperty;
590 
591         aProperty.Name  = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
592 													CFGPROPERTY_NODEPATH ) );
593 		aProperty.Value	<<= aOldParentPath;
594 		aArguments[ 0 ]	<<= aProperty;
595 
596 		xOldParentBatch = uno::Reference< util::XChangesBatch >(
597 			m_xConfigProvider->createInstanceWithArguments(
598                 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
599                     READWRITE_SERVICE_NAME ) ),
600 				aArguments ),
601 			uno::UNO_QUERY );
602 
603         OSL_ENSURE( xOldParentBatch.is(), "HierarchyEntry::move - No batch!" );
604 
605 		if ( !xOldParentBatch.is() )
606 			return sal_False;
607 
608 		if ( aOldParentPath == aNewParentPath )
609 		{
610 			bDifferentParents = sal_False;
611 			xNewParentBatch = xOldParentBatch;
612 		}
613 		else
614 		{
615 			bDifferentParents = sal_True;
616 
617 			aProperty.Name	  = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
618 													CFGPROPERTY_NODEPATH ) );
619 			aProperty.Value	<<= aNewParentPath;
620 			aArguments[ 0 ]	<<= aProperty;
621 
622 			xNewParentBatch = uno::Reference< util::XChangesBatch >(
623 				m_xConfigProvider->createInstanceWithArguments(
624                     rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
625                         READWRITE_SERVICE_NAME ) ),
626 					aArguments ),
627 				uno::UNO_QUERY );
628 
629             OSL_ENSURE(
630                 xNewParentBatch.is(), "HierarchyEntry::move - No batch!" );
631 
632 			if ( !xNewParentBatch.is() )
633 				return sal_False;
634 		}
635 	}
636 	catch ( uno::RuntimeException const & )
637 	{
638 		throw;
639 	}
640 	catch ( uno::Exception const & )
641 	{
642 		// createInstance, createInstanceWithArguments
643 
644         OSL_ENSURE( sal_False, "HierarchyEntry::move - caught Exception!" );
645 		return sal_False;
646 	}
647 
648 	//////////////////////////////////////////////////////////////////////
649 	// (1) Get entry...
650 	//////////////////////////////////////////////////////////////////////
651 
652 	uno::Any aEntry;
653 	uno::Reference< container::XNameAccess >    xOldParentNameAccess;
654 	uno::Reference< container::XNameContainer > xOldNameContainer;
655 
656 	try
657 	{
658 		xOldParentNameAccess
659 			= uno::Reference< container::XNameAccess >(
660                 xOldParentBatch, uno::UNO_QUERY );
661 
662         OSL_ENSURE( xOldParentNameAccess.is(),
663 					"HierarchyEntry::move - No name access!" );
664 
665 		if ( !xOldParentNameAccess.is() )
666 			return sal_False;
667 
668 		if ( bOldRoot )
669 		{
670 			xOldNameContainer = uno::Reference< container::XNameContainer >(
671 										xOldParentNameAccess, uno::UNO_QUERY );
672 		}
673 		else
674 		{
675 			xOldParentNameAccess->getByName(
676  				rtl::OUString::createFromAscii( "Children" ) )
677                     >>= xOldNameContainer;
678 		}
679 
680         aEntry = xOldNameContainer->getByName( m_aName );
681 	}
682 	catch ( container::NoSuchElementException const & )
683 	{
684 		// getByName
685 
686         OSL_ENSURE( sal_False,
687 					"HierarchyEntry::move - caught NoSuchElementException!" );
688 		return sal_False;
689 	}
690 	catch ( lang::WrappedTargetException const & )
691 	{
692 		// getByName
693 
694         OSL_ENSURE( sal_False,
695 					"HierarchyEntry::move - caught WrappedTargetException!" );
696 		return sal_False;
697 	}
698 
699 	//////////////////////////////////////////////////////////////////////
700 	// (2) Remove entry... Note: Insert BEFORE remove does not work!
701 	//////////////////////////////////////////////////////////////////////
702 
703 	try
704 	{
705         xOldNameContainer->removeByName( m_aName );
706 		xOldParentBatch->commitChanges();
707 	}
708 	catch ( container::NoSuchElementException const & )
709 	{
710 		// getByName, removeByName
711 
712         OSL_ENSURE( sal_False,
713 					"HierarchyEntry::move - caught NoSuchElementException!" );
714 		return sal_False;
715 	}
716 
717 	//////////////////////////////////////////////////////////////////////
718 	// (3) Insert entry at new parent...
719 	//////////////////////////////////////////////////////////////////////
720 
721 	try
722 	{
723 		uno::Reference< container::XNameReplace > xNewNameReplace;
724 		aEntry >>= xNewNameReplace;
725 
726         OSL_ENSURE( xNewNameReplace.is(),
727 					"HierarchyEntry::move - No name replace!" );
728 
729 		if ( !xNewNameReplace.is() )
730 			return sal_False;
731 
732 		uno::Reference< container::XNameAccess > xNewParentNameAccess;
733 		if ( bDifferentParents )
734 			xNewParentNameAccess
735 				= uno::Reference< container::XNameAccess >(
736                     xNewParentBatch, uno::UNO_QUERY );
737 		else
738 			xNewParentNameAccess = xOldParentNameAccess;
739 
740         OSL_ENSURE( xNewParentNameAccess.is(),
741 					"HierarchyEntry::move - No name access!" );
742 
743 		if ( !xNewParentNameAccess.is() )
744 			return sal_False;
745 
746 		uno::Reference< container::XNameContainer > xNewNameContainer;
747 		if ( bDifferentParents )
748 		{
749 			if ( bNewRoot )
750 			{
751 				xNewNameContainer
752                     = uno::Reference< container::XNameContainer >(
753                         xNewParentNameAccess, uno::UNO_QUERY );
754 			}
755 			else
756 			{
757 				xNewParentNameAccess->getByName(
758  					rtl::OUString::createFromAscii( "Children" ) )
759 						>>= xNewNameContainer;
760 			}
761 		}
762 		else
763 			xNewNameContainer = xOldNameContainer;
764 
765 		if ( !xNewNameContainer.is() )
766 			return sal_False;
767 
768 		xNewNameReplace->replaceByName(
769             rtl::OUString::createFromAscii( "Title" ),
770             uno::makeAny( rData.getTitle() ) );
771 
772         // TargetURL property may contain a reference to the Office
773         // installation directory. To ensure a reloctable office
774         // installation, the path to the office installtion
775         // directory must never be stored directly. Use a placeholder
776         // instead.
777         rtl::OUString aValue( rData.getTargetURL() );
778         if ( m_xOfficeInstDirs.is() && ( aValue.getLength() > 0 ) )
779             aValue = m_xOfficeInstDirs->makeRelocatableURL( aValue );
780 		xNewNameReplace->replaceByName(
781             rtl::OUString::createFromAscii( "TargetURL" ),
782             uno::makeAny( aValue ) );
783         sal_Int32 nType = rData.getType() == HierarchyEntryData::LINK ? 0 : 1;
784         xNewNameReplace->replaceByName(
785             rtl::OUString::createFromAscii( "Type" ),
786             uno::makeAny( nType ) );
787 
788 		xNewNameContainer->insertByName( aNewKey, aEntry );
789 		xNewParentBatch->commitChanges();
790 	}
791 	catch ( container::NoSuchElementException const & )
792 	{
793 		// replaceByName, insertByName, getByName
794 
795         OSL_ENSURE( sal_False,
796 					"HierarchyEntry::move - caught NoSuchElementException!" );
797 		return sal_False;
798 	}
799 	catch ( lang::IllegalArgumentException const & )
800 	{
801 		// replaceByName, insertByName
802 
803         OSL_ENSURE(
804             sal_False,
805             "HierarchyEntry::move - caught IllegalArgumentException!" );
806 		return sal_False;
807 	}
808 	catch ( container::ElementExistException const & )
809 	{
810 		// insertByName
811 
812         OSL_ENSURE( sal_False,
813 					"HierarchyEntry::move - caught ElementExistException!" );
814 		return sal_False;
815 	}
816 	catch ( lang::WrappedTargetException const & )
817 	{
818 		// replaceByName, insertByName, getByName
819 
820         OSL_ENSURE( sal_False,
821 					"HierarchyEntry::move - caught WrappedTargetException!" );
822 		return sal_False;
823 	}
824 
825 #if 0
826 	//////////////////////////////////////////////////////////////////////
827 	// (4) Commit changes...
828 	//////////////////////////////////////////////////////////////////////
829 
830 	try
831 	{
832 		xNewParentBatch->commitChanges();
833 
834 		if ( bDifferentParents )
835 			xOldParentBatch->commitChanges();
836 	}
837 	catch ( lang::WrappedTargetException const & )
838 	{
839 		// commitChanges
840 
841         OSL_ENSURE( sal_False,
842 					"HierarchyEntry::move - caught WrappedTargetException!" );
843 		return sal_False;
844 	}
845 #endif
846 
847 	return sal_True;
848 #endif
849 }
850 
851 //=========================================================================
remove()852 sal_Bool HierarchyEntry::remove()
853 {
854 	try
855 	{
856 		osl::Guard< osl::Mutex > aGuard( m_aMutex );
857 
858 		if ( !m_xConfigProvider.is() )
859 			m_xConfigProvider = uno::Reference< lang::XMultiServiceFactory >(
860                 m_xSMgr->createInstance( m_aServiceSpecifier ),
861 				uno::UNO_QUERY );
862 
863 		if ( m_xConfigProvider.is() )
864 		{
865 			// Create parent's key. It must exist!
866 
867             rtl::OUString aParentPath;
868 			sal_Bool bRoot = sal_True;
869 
870 			sal_Int32 nPos = m_aPath.lastIndexOf( '/' );
871 			if ( nPos != -1 )
872 			{
873 				// Skip "/Children" segment of the path, too.
874 				nPos = m_aPath.lastIndexOf( '/', nPos - 1 );
875 
876                 OSL_ENSURE( nPos != -1,
877 							"HierarchyEntry::remove - Wrong path!" );
878 
879 				aParentPath += m_aPath.copy( 0, nPos );
880 				bRoot = sal_False;
881 			}
882 
883             uno::Sequence< uno::Any > aArguments( 1 );
884 			beans::PropertyValue	  aProperty;
885 
886 			aProperty.Name	  = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
887 													CFGPROPERTY_NODEPATH ) );
888 			aProperty.Value	<<= aParentPath;
889 			aArguments[ 0 ]	<<= aProperty;
890 
891 			uno::Reference< util::XChangesBatch > xBatch(
892 				m_xConfigProvider->createInstanceWithArguments(
893                     rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
894                         READWRITE_SERVICE_NAME ) ),
895 					aArguments ),
896 				uno::UNO_QUERY );
897 
898             OSL_ENSURE( xBatch.is(),
899 						"HierarchyEntry::remove - No batch!" );
900 
901 			uno::Reference< container::XNameAccess > xParentNameAccess(
902                 xBatch, uno::UNO_QUERY );
903 
904             OSL_ENSURE( xParentNameAccess.is(),
905 						"HierarchyEntry::remove - No name access!" );
906 
907 			if ( xBatch.is() && xParentNameAccess.is() )
908 			{
909 				uno::Reference< container::XNameContainer > xContainer;
910 
911 				if ( bRoot )
912 				{
913 					// Special handling for children of root,
914 					// which is not an entry. It's only a set
915 					// of entries.
916 					xContainer = uno::Reference< container::XNameContainer >(
917                         xParentNameAccess, uno::UNO_QUERY );
918 				}
919 				else
920 				{
921 					// Append new entry to parents child list,
922 					// which is a set of entries.
923  					xParentNameAccess->getByName(
924                         rtl::OUString::createFromAscii( "Children" ) )
925                             >>= xContainer;
926 				}
927 
928                 OSL_ENSURE( xContainer.is(),
929 							"HierarchyEntry::remove - No container!" );
930 
931 				if ( xContainer.is() )
932 				{
933                     xContainer->removeByName( m_aName );
934 					xBatch->commitChanges();
935 					return sal_True;
936 				}
937 			}
938 		}
939 	}
940 	catch ( uno::RuntimeException const & )
941 	{
942 		throw;
943 	}
944 	catch ( container::NoSuchElementException const & )
945 	{
946 		// getByName, removeByName
947 
948         OSL_ENSURE(
949             sal_False,
950             "HierarchyEntry::remove - caught NoSuchElementException!" );
951 	}
952 	catch ( lang::WrappedTargetException const & )
953 	{
954 		// getByName, commitChanges
955 
956         OSL_ENSURE(
957             sal_False,
958             "HierarchyEntry::remove - caught WrappedTargetException!" );
959 	}
960 	catch ( uno::Exception const & )
961 	{
962 		// createInstance, createInstanceWithArguments
963 
964         OSL_ENSURE( sal_False,
965 					"HierarchyEntry::remove - caught Exception!" );
966 	}
967 
968 	return sal_False;
969 }
970 
971 //=========================================================================
first(iterator & it)972 sal_Bool HierarchyEntry::first( iterator& it )
973 {
974 	osl::Guard< osl::Mutex > aGuard( m_aMutex );
975 
976 	if ( it.m_pImpl->pos == -1 )
977 	{
978 		// Init...
979 
980 		try
981 		{
982 			uno::Reference< container::XHierarchicalNameAccess >
983                 xRootHierNameAccess = getRootReadAccess();
984 
985 			if ( xRootHierNameAccess.is() )
986 			{
987 				uno::Reference< container::XNameAccess > xNameAccess;
988 
989 				if ( m_aPath.getLength() > 0 )
990 				{
991 					rtl::OUString aPath = m_aPath;
992 					aPath += rtl::OUString::createFromAscii( "/Children" );
993 
994 					xRootHierNameAccess->getByHierarchicalName( aPath )
995 						>>= xNameAccess;
996 				}
997 				else
998 					xNameAccess
999 						= uno::Reference< container::XNameAccess >(
1000 								xRootHierNameAccess, uno::UNO_QUERY );
1001 
1002                 OSL_ENSURE( xNameAccess.is(),
1003 							"HierarchyEntry::first - No name access!" );
1004 
1005 				if ( xNameAccess.is() )
1006 					it.m_pImpl->names = xNameAccess->getElementNames();
1007 
1008 				uno::Reference< container::XHierarchicalNameAccess >
1009                     xHierNameAccess( xNameAccess, uno::UNO_QUERY );
1010 
1011                 OSL_ENSURE( xHierNameAccess.is(),
1012 							"HierarchyEntry::first - No hier. name access!" );
1013 
1014 				it.m_pImpl->dir = xHierNameAccess;
1015 
1016                 it.m_pImpl->officeDirs = m_xOfficeInstDirs;
1017 			}
1018 		}
1019 		catch ( uno::RuntimeException const & )
1020 		{
1021 			throw;
1022 		}
1023 		catch ( container::NoSuchElementException const& )
1024 		{
1025 			// getByHierarchicalName
1026 
1027             OSL_ENSURE(
1028                 sal_False,
1029                 "HierarchyEntry::first - caught NoSuchElementException!" );
1030 		}
1031 		catch ( uno::Exception const & )
1032 		{
1033             OSL_ENSURE( sal_False,
1034 					"HierarchyEntry::first - caught Exception!" );
1035 		}
1036 	}
1037 
1038 	if ( it.m_pImpl->names.getLength() == 0 )
1039 		return sal_False;
1040 
1041 	it.m_pImpl->pos = 0;
1042 	return sal_True;
1043 }
1044 
1045 //=========================================================================
next(iterator & it)1046 sal_Bool HierarchyEntry::next( iterator& it )
1047 {
1048 	osl::Guard< osl::Mutex > aGuard( m_aMutex );
1049 
1050 	if ( it.m_pImpl->pos == -1 )
1051 		return first( it );
1052 
1053 	++(it.m_pImpl->pos);
1054 
1055 	return ( it.m_pImpl->pos < it.m_pImpl->names.getLength() );
1056 }
1057 
1058 //=========================================================================
createPathFromHierarchyURL(const HierarchyUri & rURI)1059 rtl::OUString HierarchyEntry::createPathFromHierarchyURL(
1060     const HierarchyUri& rURI )
1061 {
1062 	// Transform path....
1063     // folder/subfolder/subsubfolder
1064     //      --> ['folder']/Children/['subfolder']/Children/['subsubfolder']
1065 
1066     const rtl::OUString aPath = rURI.getPath().copy( 1 ); // skip leading slash.
1067 	sal_Int32 nLen = aPath.getLength();
1068 
1069 	if ( nLen )
1070 	{
1071         rtl::OUStringBuffer aNewPath;
1072         aNewPath.appendAscii( "['" );
1073 
1074 		sal_Int32 nStart = 0;
1075 		sal_Int32 nEnd   = aPath.indexOf( '/' );
1076 
1077 		do
1078 		{
1079 			if ( nEnd == -1 )
1080 				nEnd = nLen;
1081 
1082 			rtl::OUString aToken = aPath.copy( nStart, nEnd - nStart );
1083             makeXMLName( aToken, aNewPath );
1084 
1085 			if ( nEnd != nLen )
1086 			{
1087                 aNewPath.appendAscii( "']/Children/['" );
1088 				nStart = nEnd + 1;
1089                 nEnd   = aPath.indexOf( '/', nStart );
1090 			}
1091             else
1092                 aNewPath.appendAscii( "']" );
1093 		}
1094 		while ( nEnd != nLen );
1095 
1096         return aNewPath.makeStringAndClear();
1097 	}
1098 
1099     return aPath;
1100 }
1101 
1102 //=========================================================================
1103 uno::Reference< container::XHierarchicalNameAccess >
getRootReadAccess()1104 HierarchyEntry::getRootReadAccess()
1105 {
1106 	if ( !m_xRootReadAccess.is() )
1107 	{
1108 		osl::Guard< osl::Mutex > aGuard( m_aMutex );
1109 		if ( !m_xRootReadAccess.is() )
1110 		{
1111 			if ( m_bTriedToGetRootReadAccess ) // #82494#
1112 			{
1113 				OSL_ENSURE( sal_False,
1114 							"HierarchyEntry::getRootReadAccess - "
1115 							"Unable to read any config data! -> #82494#" );
1116 				return uno::Reference< container::XHierarchicalNameAccess >();
1117 			}
1118 
1119 			try
1120 			{
1121 				if ( !m_xConfigProvider.is() )
1122 					m_xConfigProvider
1123                         = uno::Reference< lang::XMultiServiceFactory >(
1124                             m_xSMgr->createInstance( m_aServiceSpecifier ),
1125                             uno::UNO_QUERY );
1126 
1127 				if ( m_xConfigProvider.is() )
1128 				{
1129 					// Create Root object.
1130 
1131 					uno::Sequence< uno::Any > aArguments( 1 );
1132                     beans::PropertyValue      aProperty;
1133                     aProperty.Name = rtl::OUString(
1134                         RTL_CONSTASCII_USTRINGPARAM( CFGPROPERTY_NODEPATH ) );
1135                     aProperty.Value <<= rtl::OUString(); // root path
1136                     aArguments[ 0 ] <<= aProperty;
1137 
1138 					m_bTriedToGetRootReadAccess = sal_True;
1139 
1140 					m_xRootReadAccess
1141                         = uno::Reference< container::XHierarchicalNameAccess >(
1142                             m_xConfigProvider->createInstanceWithArguments(
1143                                 rtl::OUString(
1144                                     RTL_CONSTASCII_USTRINGPARAM(
1145                                         READ_SERVICE_NAME ) ),
1146                                 aArguments ),
1147                             uno::UNO_QUERY );
1148 				}
1149 			}
1150 			catch ( uno::RuntimeException const & )
1151 			{
1152 				throw;
1153 			}
1154 			catch ( uno::Exception const & )
1155 			{
1156 				// createInstance, createInstanceWithArguments
1157 
1158                 OSL_ENSURE( sal_False,
1159 							"HierarchyEntry::getRootReadAccess - "
1160 							"caught Exception!" );
1161 			}
1162 		}
1163 	}
1164 	return m_xRootReadAccess;
1165 }
1166 
1167 //=========================================================================
1168 //=========================================================================
1169 //
1170 // HierarchyEntry::iterator Implementation.
1171 //
1172 //=========================================================================
1173 //=========================================================================
1174 
iterator()1175 HierarchyEntry::iterator::iterator()
1176 {
1177 	m_pImpl = new iterator_Impl;
1178 }
1179 
1180 //=========================================================================
~iterator()1181 HierarchyEntry::iterator::~iterator()
1182 {
1183 	delete m_pImpl;
1184 }
1185 
1186 //=========================================================================
operator *() const1187 const HierarchyEntryData& HierarchyEntry::iterator::operator*() const
1188 {
1189 	if ( ( m_pImpl->pos != -1 )
1190 		 && ( m_pImpl->dir.is() )
1191 		 && ( m_pImpl->pos < m_pImpl->names.getLength() ) )
1192 	{
1193 		try
1194 		{
1195             rtl::OUStringBuffer aKey;
1196             aKey.appendAscii( "['" );
1197             makeXMLName( m_pImpl->names.getConstArray()[ m_pImpl->pos ], aKey );
1198             aKey.appendAscii( "']" );
1199 
1200             rtl::OUString aTitle     = aKey.makeStringAndClear();
1201             rtl::OUString aTargetURL = aTitle;
1202             rtl::OUString aType      = aTitle;
1203 
1204 			aTitle     += rtl::OUString::createFromAscii( "/Title" );
1205 			aTargetURL += rtl::OUString::createFromAscii( "/TargetURL" );
1206             aType      += rtl::OUString::createFromAscii( "/Type" );
1207 
1208             rtl::OUString aValue;
1209             m_pImpl->dir->getByHierarchicalName( aTitle ) >>= aValue;
1210             m_pImpl->entry.setTitle( aValue );
1211 
1212             m_pImpl->dir->getByHierarchicalName( aTargetURL ) >>= aValue;
1213 
1214             // TargetURL property may contain a reference to the Office
1215             // installation directory. To ensure a reloctable office
1216             // installation, the path to the office installtion directory must
1217             // never be stored directly. A placeholder is used instead. Replace
1218             // it by actual installation directory.
1219             if ( m_pImpl->officeDirs.is() && ( aValue.getLength() > 0 ) )
1220                 aValue = m_pImpl->officeDirs->makeAbsoluteURL( aValue );
1221             m_pImpl->entry.setTargetURL( aValue );
1222 
1223             if ( m_pImpl->dir->hasByHierarchicalName( aType ) )
1224             {
1225                 // Might not be present since it was introduced long
1226                 // after Title and TargetURL (#82433#)... So not getting
1227                 // it is not an error.
1228 
1229                 // Get Type value.
1230                 sal_Int32 nType = 0;
1231                 if ( m_pImpl->dir->getByHierarchicalName( aType ) >>= nType )
1232                 {
1233                     if ( nType == 0 )
1234                     {
1235                         m_pImpl->entry.setType( HierarchyEntryData::LINK );
1236                     }
1237                     else if ( nType == 1 )
1238                     {
1239                         m_pImpl->entry.setType( HierarchyEntryData::FOLDER );
1240                     }
1241                     else
1242                     {
1243                         OSL_ENSURE( sal_False,
1244                                     "HierarchyEntry::getData - "
1245                                     "Unknown Type value!" );
1246                     }
1247                 }
1248             }
1249 
1250             m_pImpl->entry.setName(
1251                 m_pImpl->names.getConstArray()[ m_pImpl->pos ] );
1252 		}
1253         catch ( container::NoSuchElementException const & )
1254 		{
1255 			m_pImpl->entry = HierarchyEntryData();
1256 		}
1257 	}
1258 
1259 	return m_pImpl->entry;
1260 }
1261 
1262 } // namespace hierarchy_ucp
1263