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