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