1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_stoc.hxx"
30 
31 //=========================================================================
32 // Todo:
33 //
34 // - closeKey() calls (according to JSC not really needed because XRegistry
35 //   implementation closes key in it's dtor.
36 //
37 //=========================================================================
38 #include <osl/diagnose.h>
39 #include <rtl/ustrbuf.hxx>
40 #include "com/sun/star/reflection/XPublished.hpp"
41 #include "cppuhelper/implbase1.hxx"
42 #include "registry/reader.hxx"
43 #include "registry/version.h"
44 #include "base.hxx"
45 #include "rdbtdp_tdenumeration.hxx"
46 
47 using namespace com::sun::star;
48 
49 namespace {
50 
51 class IndividualConstantTypeDescriptionImpl:
52     public cppu::ImplInheritanceHelper1<
53         stoc_rdbtdp::ConstantTypeDescriptionImpl,
54         com::sun::star::reflection::XPublished >
55 {
56 public:
57     IndividualConstantTypeDescriptionImpl(
58         rtl::OUString const & name, com::sun::star::uno::Any const & value,
59         bool published):
60         cppu::ImplInheritanceHelper1<
61             stoc_rdbtdp::ConstantTypeDescriptionImpl,
62             com::sun::star::reflection::XPublished >(name, value),
63         m_published(published) {}
64 
65     virtual sal_Bool SAL_CALL isPublished()
66         throw (::com::sun::star::uno::RuntimeException)
67     { return m_published; }
68 
69 private:
70     bool m_published;
71 };
72 
73 }
74 
75 namespace stoc_rdbtdp
76 {
77 
78 //=========================================================================
79 //=========================================================================
80 //
81 // TypeDescriptionEnumerationImpl Implementation.
82 //
83 //=========================================================================
84 //=========================================================================
85 
86 // static
87 rtl::Reference< TypeDescriptionEnumerationImpl >
88 TypeDescriptionEnumerationImpl::createInstance(
89         const uno::Reference< container::XHierarchicalNameAccess > & xTDMgr,
90         const rtl::OUString & rModuleName,
91         const uno::Sequence< uno::TypeClass > & rTypes,
92         reflection::TypeDescriptionSearchDepth eDepth,
93         const RegistryKeyList & rBaseKeys )
94     throw ( reflection::NoSuchTypeNameException,
95             reflection::InvalidTypeNameException,
96             uno::RuntimeException )
97 {
98     if ( rModuleName.getLength() == 0 )
99     {
100         // Enumeration for root requested.
101         return rtl::Reference< TypeDescriptionEnumerationImpl >(
102             new TypeDescriptionEnumerationImpl(
103                 xTDMgr, rBaseKeys, rTypes, eDepth ) );
104     }
105 
106     RegistryKeyList aModuleKeys;
107 
108     rtl::OUString aKey( rModuleName.replace( '.', '/' ) );
109 
110     bool bOpenKeySucceeded = false;
111 
112     const RegistryKeyList::const_iterator end = rBaseKeys.end();
113     RegistryKeyList::const_iterator it = rBaseKeys.begin();
114 
115     while ( it != end )
116     {
117         uno::Reference< registry::XRegistryKey > xKey;
118         try
119         {
120             xKey = (*it)->openKey( aKey );
121             if ( xKey.is() )
122             {
123                 // closes key in it's dtor (which is
124                 // called even in case of exceptions).
125                 RegistryKeyCloser aCloser( xKey );
126 
127                 if ( xKey->isValid() )
128                 {
129                     bOpenKeySucceeded = true;
130 
131                     if ( xKey->getValueType()
132                          == registry::RegistryValueType_BINARY )
133                     {
134                         uno::Sequence< sal_Int8 > aBytes(
135                             xKey->getBinaryValue() );
136 
137                         typereg::Reader aReader(
138                             aBytes.getConstArray(), aBytes.getLength(), false,
139                             TYPEREG_VERSION_1);
140 
141                         rtl::OUString aName(
142                             aReader.getTypeName().replace( '/', '.' ) );
143 
144                         if ( aReader.getTypeClass() == RT_TYPE_MODULE )
145                         {
146                             // Do not close xKey!
147                             aCloser.reset();
148 
149                             aModuleKeys.push_back( xKey );
150                         }
151                     }
152                 }
153                 else
154                 {
155                     OSL_ENSURE(
156                         sal_False,
157                         "TypeDescriptionEnumerationImpl::createInstance "
158                         "- Invalid registry key!" );
159                 }
160             }
161         }
162         catch ( registry::InvalidRegistryException const & )
163         {
164             // openKey, getValueType, getBinaryValue
165 
166             OSL_ENSURE( sal_False,
167                         "TypeDescriptionEnumerationImpl::createInstance "
168                         "- Caught InvalidRegistryException!" );
169         }
170 
171         it++;
172     }
173 
174     if ( !bOpenKeySucceeded )
175         throw reflection::NoSuchTypeNameException();
176 
177     if ( aModuleKeys.size() == 0 )
178         throw reflection::InvalidTypeNameException();
179 
180     return rtl::Reference< TypeDescriptionEnumerationImpl >(
181         new TypeDescriptionEnumerationImpl(
182                 xTDMgr, aModuleKeys, rTypes, eDepth ) );
183 }
184 
185 //=========================================================================
186 TypeDescriptionEnumerationImpl::TypeDescriptionEnumerationImpl(
187     const uno::Reference< container::XHierarchicalNameAccess > & xTDMgr,
188     const RegistryKeyList & rModuleKeys,
189     const uno::Sequence< uno::TypeClass > & rTypes,
190     reflection::TypeDescriptionSearchDepth eDepth )
191 : m_aModuleKeys( rModuleKeys ),
192   m_aTypes( rTypes ),
193   m_eDepth( eDepth ),
194   m_xTDMgr( xTDMgr )
195 {
196     g_moduleCount.modCnt.acquire( &g_moduleCount.modCnt );
197 }
198 
199 //=========================================================================
200 // virtual
201 TypeDescriptionEnumerationImpl::~TypeDescriptionEnumerationImpl()
202 {
203     RegistryKeyList::const_iterator it = m_aModuleKeys.begin();
204     RegistryKeyList::const_iterator end = m_aModuleKeys.end();
205 /*
206    @@@ in case we enumerate root and queryMore was never called, then
207        m_aModuleKeys contains open root keys which where passed from
208        tdprov and must not be closed by us.
209 
210     while ( it != end )
211     {
212         try
213         {
214             if ( (*it)->isValid() )
215                 (*it)->closeKey();
216         }
217         catch (...)
218         {
219             // No exceptions from dtors, please!
220             OSL_ENSURE( sal_False,
221             "TypeDescriptionEnumerationImpl::~TypeDescriptionEnumerationImpl "
222             "- Caught exception!" );
223         }
224 
225         it++;
226     }
227 */
228     it = m_aCurrentModuleSubKeys.begin();
229     end = m_aCurrentModuleSubKeys.end();
230     while ( it != end )
231     {
232         try
233         {
234             if ( (*it)->isValid() )
235                 (*it)->closeKey();
236         }
237         catch (Exception &)
238         {
239             // No exceptions from dtors, please!
240             OSL_ENSURE( sal_False,
241             "TypeDescriptionEnumerationImpl::~TypeDescriptionEnumerationImpl "
242             "- Caught exception!" );
243         }
244 
245         it++;
246     }
247 
248     g_moduleCount.modCnt.release( &g_moduleCount.modCnt );
249 }
250 
251 //=========================================================================
252 //
253 // XEnumeration (base of XTypeDescriptionEnumeration) methods
254 //
255 //=========================================================================
256 
257 // virtual
258 sal_Bool SAL_CALL TypeDescriptionEnumerationImpl::hasMoreElements()
259     throw ( uno::RuntimeException )
260 {
261     return queryMore();
262 }
263 
264 //=========================================================================
265 // virtual
266 uno::Any SAL_CALL TypeDescriptionEnumerationImpl::nextElement()
267     throw ( container::NoSuchElementException,
268             lang::WrappedTargetException,
269             uno::RuntimeException )
270 {
271     return uno::Any( uno::makeAny( nextTypeDescription() ) );
272 }
273 
274 //=========================================================================
275 //
276 // XTypeDescriptionEnumeration methods
277 //
278 //=========================================================================
279 
280 // virtual
281 uno::Reference< reflection::XTypeDescription > SAL_CALL
282 TypeDescriptionEnumerationImpl::nextTypeDescription()
283     throw ( container::NoSuchElementException,
284             uno::RuntimeException )
285 {
286     uno::Reference< reflection::XTypeDescription > xTD( queryNext() );
287 
288     if ( xTD.is() )
289         return xTD;
290 
291     throw container::NoSuchElementException(
292         rtl::OUString::createFromAscii(
293             "No further elements in enumeration!" ),
294         static_cast< cppu::OWeakObject * >( this  ) );
295 }
296 
297 //=========================================================================
298 bool TypeDescriptionEnumerationImpl::match(
299     RTTypeClass eType1, uno::TypeClass eType2 )
300 {
301     switch ( eType1 )
302     {
303     case RT_TYPE_INTERFACE:
304         return eType2 == uno::TypeClass_INTERFACE;
305 
306     case RT_TYPE_MODULE:
307         return eType2 == uno::TypeClass_MODULE;
308 
309     case RT_TYPE_STRUCT:
310         return eType2 == uno::TypeClass_STRUCT;
311 
312     case RT_TYPE_ENUM:
313         return eType2 == uno::TypeClass_ENUM;
314 
315     case RT_TYPE_EXCEPTION:
316         return eType2 == uno::TypeClass_EXCEPTION;
317 
318     case RT_TYPE_TYPEDEF:
319         return eType2 == uno::TypeClass_TYPEDEF;
320 
321     case RT_TYPE_SERVICE:
322         return eType2 == uno::TypeClass_SERVICE;
323 
324     case RT_TYPE_SINGLETON:
325         return eType2 == uno::TypeClass_SINGLETON;
326 
327     case RT_TYPE_CONSTANTS:
328         return eType2 == uno::TypeClass_CONSTANTS;
329 
330     case RT_TYPE_UNION:
331         return eType2 == uno::TypeClass_UNION;
332 
333     default:
334         return false;
335     }
336 }
337 
338 //=========================================================================
339 bool TypeDescriptionEnumerationImpl::queryMore()
340 {
341     osl::MutexGuard aGuard( m_aMutex );
342 
343     for (;;)
344     {
345         if ( !m_aCurrentModuleSubKeys.empty() || !m_aTypeDescs.empty() )
346         {
347             // Okay, there is at least one more element.
348             return true;
349         }
350 
351         if ( m_aModuleKeys.empty() )
352         {
353             // No module keys (therefore no elements) left.
354             return false;
355         }
356 
357         // Note: m_aCurrentModuleSubKeys is always empty AND m_aModuleKeys is
358         //       never empty when ariving here.
359         //       ==> select new module key, fill m_aCurrentModuleSubKeys
360 
361         uno::Sequence< uno::Reference< registry::XRegistryKey > > aKeys;
362         try
363         {
364             aKeys = m_aModuleKeys.front()->openKeys();
365             for ( sal_Int32 n = 0; n < aKeys.getLength(); ++n )
366             {
367                 uno::Reference< registry::XRegistryKey > xKey = aKeys[ n ];
368 
369                 // closes key in it's dtor (which is
370                 // called even in case of exceptions).
371                 RegistryKeyCloser aCloser( xKey );
372 
373                 try
374                 {
375                     if ( xKey->isValid() )
376                     {
377                         if ( xKey->getValueType()
378                                 == registry::RegistryValueType_BINARY )
379                         {
380                             bool bIncludeIt = (m_aTypes.getLength() == 0);
381                             bool bNeedTypeClass =
382                                 ((m_aTypes.getLength() > 0) ||
383                                  (m_eDepth
384                                     == reflection::TypeDescriptionSearchDepth_INFINITE));
385                             if ( bNeedTypeClass )
386                             {
387                                 uno::Sequence< sal_Int8 > aBytes(
388                                     xKey->getBinaryValue() );
389 
390                                 typereg::Reader aReader(
391                                     aBytes.getConstArray(), aBytes.getLength(),
392                                     false, TYPEREG_VERSION_1);
393 
394                                 RTTypeClass eTypeClass = aReader.getTypeClass();
395 
396                                 // Does key match requested types? Empty
397                                 // sequence means include all.
398                                 if ( m_aTypes.getLength() > 0 )
399                                 {
400                                     for ( sal_Int32 m = 0;
401                                           m < m_aTypes.getLength();
402                                           ++m )
403                                     {
404                                         if ( match(eTypeClass, m_aTypes[ m ]) )
405                                         {
406                                             bIncludeIt = true;
407                                             break;
408                                         }
409                                     }
410                                 }
411 
412                                 if ( m_eDepth ==
413                                         reflection::TypeDescriptionSearchDepth_INFINITE )
414                                 {
415                                     if ( eTypeClass == RT_TYPE_MODULE )
416                                     {
417                                         // Do not close xKey!
418                                         aCloser.reset();
419 
420                                         // Remember new module key.
421                                         m_aModuleKeys.push_back( xKey );
422                                     }
423                                 }
424                             }
425 
426                             if ( bIncludeIt )
427                             {
428                                 // Do not close xKey!
429                                 aCloser.reset();
430 
431                                 m_aCurrentModuleSubKeys.push_back( xKey );
432                             }
433                         }
434                     }
435                     else
436                     {
437                         OSL_ENSURE( sal_False,
438                             "TypeDescriptionEnumerationImpl::queryMore "
439                             "- Invalid registry key!" );
440                     }
441 
442                 }
443                 catch ( registry::InvalidRegistryException const & )
444                 {
445                     // getValueType, getBinaryValue
446 
447                     OSL_ENSURE( sal_False,
448                                 "TypeDescriptionEnumerationImpl::queryMore "
449                                 "- Caught InvalidRegistryException!" );
450 
451                     // Don't stop iterating!
452                 }
453             }
454         }
455         catch ( registry::InvalidRegistryException const & )
456         {
457             // openKeys
458 
459             for ( sal_Int32 n = 0; n < aKeys.getLength(); ++n )
460             {
461                 try
462                 {
463                     aKeys[ n ]->closeKey();
464                 }
465                 catch ( registry::InvalidRegistryException const & )
466                 {
467                     OSL_ENSURE( sal_False,
468                                 "TypeDescriptionEnumerationImpl::queryMore "
469                                 "- Caught InvalidRegistryException!" );
470                 }
471             }
472         }
473 
474         /////////////////////////////////////////////////////////////////////
475         // Special handling for constants contained directly in module.
476         /////////////////////////////////////////////////////////////////////
477 
478         // Constants requested?
479         bool bIncludeConstants = ( m_aTypes.getLength() == 0 );
480         if ( !bIncludeConstants )
481         {
482             for ( sal_Int32 m = 0; m < m_aTypes.getLength(); ++m )
483             {
484                 if ( m_aTypes[ m ] == uno::TypeClass_CONSTANT )
485                 {
486                     bIncludeConstants = true;
487                     break;
488                 }
489             }
490 
491         }
492 
493         if ( bIncludeConstants )
494         {
495             if ( m_aModuleKeys.front()->getValueType()
496                     == registry::RegistryValueType_BINARY )
497             {
498                 try
499                 {
500                     uno::Sequence< sal_Int8 > aBytes(
501                         m_aModuleKeys.front()->getBinaryValue() );
502 
503                     typereg::Reader aReader(
504                         aBytes.getConstArray(), aBytes.getLength(), false,
505                         TYPEREG_VERSION_1);
506 
507                     if ( aReader.getTypeClass() == RT_TYPE_MODULE )
508                     {
509                         sal_uInt16 nFields = aReader.getFieldCount();
510                         while ( nFields-- )
511                         {
512                             rtl::OUStringBuffer aName(
513                                 aReader.getTypeName().replace( '/', '.' ) );
514                             aName.appendAscii( "." );
515                             aName.append( aReader.getFieldName( nFields ) );
516 
517                             uno::Any aValue(
518                                 getRTValue(
519                                     aReader.getFieldValue( nFields ) ) );
520 
521                             m_aTypeDescs.push_back(
522                                 new IndividualConstantTypeDescriptionImpl(
523                                     aName.makeStringAndClear(), aValue,
524                                     ( ( aReader.getFieldFlags( nFields )
525                                         & RT_ACCESS_PUBLISHED )
526                                       != 0 ) ) );
527                         }
528                     }
529                 }
530                 catch ( registry::InvalidRegistryException const & )
531                 {
532                     // getBinaryValue
533 
534                     OSL_ENSURE( sal_False,
535                                 "TypeDescriptionEnumerationImpl::queryMore "
536                                 "- Caught InvalidRegistryException!" );
537                 }
538             }
539         }
540 
541         /////////////////////////////////////////////////////////////////////
542 
543 /*
544    @@@ m_aModuleKeys.front() may have open sub keys (may be contained in
545        both m_aModuleKeys and m_aCurrentModuleSubKeys)!
546 
547         try
548         {
549            m_aModuleKeys.front()->closeKey();
550         }
551         catch ( registry::InvalidRegistryException const & )
552         {
553             OSL_ENSURE( sal_False,
554                         "TypeDescriptionEnumerationImpl::queryMore "
555                         "- Caught InvalidRegistryException!" );
556         }
557 */
558         // We're done with this module key, even if there were errors.
559         m_aModuleKeys.pop_front();
560     }
561 
562     // unreachable
563 }
564 
565 //=========================================================================
566 uno::Reference< reflection::XTypeDescription >
567 TypeDescriptionEnumerationImpl::queryNext()
568 {
569     osl::MutexGuard aGuard( m_aMutex );
570 
571     for (;;)
572     {
573         if ( !queryMore() )
574             return uno::Reference< reflection::XTypeDescription >();
575 
576         uno::Reference< reflection::XTypeDescription > xTD;
577 
578         if ( !m_aTypeDescs.empty() )
579         {
580             xTD = m_aTypeDescs.front();
581             m_aTypeDescs.pop_front();
582             return xTD;
583         }
584 
585         // Note: xKey is already opened.
586         uno::Reference< registry::XRegistryKey >
587             xKey( m_aCurrentModuleSubKeys.front() );
588 /*
589    @@@ xKey may still be contained in m_aModuleKeys, too
590 
591         // closes key in it's dtor (which is
592         // called even in case of exceptions).
593         RegistryKeyCloser aCloser( xKey );
594 */
595         try
596         {
597             {
598                 if ( xKey->isValid() )
599                 {
600                     if ( xKey->getValueType()
601                             == registry::RegistryValueType_BINARY )
602                     {
603                         uno::Sequence< sal_Int8 > aBytes(
604                             xKey->getBinaryValue() );
605 
606                         xTD = createTypeDescription( aBytes,
607                                                      m_xTDMgr,
608                                                      false );
609                         OSL_ENSURE( xTD.is(),
610                             "TypeDescriptionEnumerationImpl::queryNext "
611                             "- No XTypeDescription created!" );
612                     }
613                 }
614                 else
615                 {
616                     OSL_ENSURE( sal_False,
617                         "TypeDescriptionEnumerationImpl::queryNext "
618                         "- Invalid registry key!" );
619                 }
620             }
621         }
622         catch ( registry::InvalidRegistryException const & )
623         {
624             // getValueType, getBinaryValue
625 
626             OSL_ENSURE( sal_False,
627                         "TypeDescriptionEnumerationImpl::queryNext "
628                         "- Caught InvalidRegistryException!" );
629         }
630 
631         // We're done with this key, even if there were errors.
632         m_aCurrentModuleSubKeys.pop_front();
633 
634         if ( xTD.is() )
635             return xTD;
636 
637         // next try...
638 
639     } // for (;;)
640 }
641 
642 } // namespace stoc_rdbtdp
643 
644