blob: d74671e38840f18bf95dda145458a334494a4b46 [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_stoc.hxx"
//=========================================================================
// Todo:
//
// - closeKey() calls (according to JSC not really needed because XRegistry
// implementation closes key in it's dtor.
//
//=========================================================================
#include <osl/diagnose.h>
#include <rtl/ustrbuf.hxx>
#include "com/sun/star/reflection/XPublished.hpp"
#include "cppuhelper/implbase1.hxx"
#include "registry/reader.hxx"
#include "registry/version.h"
#include "base.hxx"
#include "rdbtdp_tdenumeration.hxx"
using namespace com::sun::star;
namespace {
class IndividualConstantTypeDescriptionImpl:
public cppu::ImplInheritanceHelper1<
stoc_rdbtdp::ConstantTypeDescriptionImpl,
com::sun::star::reflection::XPublished >
{
public:
IndividualConstantTypeDescriptionImpl(
rtl::OUString const & name, com::sun::star::uno::Any const & value,
bool published):
cppu::ImplInheritanceHelper1<
stoc_rdbtdp::ConstantTypeDescriptionImpl,
com::sun::star::reflection::XPublished >(name, value),
m_published(published) {}
virtual sal_Bool SAL_CALL isPublished()
throw (::com::sun::star::uno::RuntimeException)
{ return m_published; }
private:
bool m_published;
};
}
namespace stoc_rdbtdp
{
//=========================================================================
//=========================================================================
//
// TypeDescriptionEnumerationImpl Implementation.
//
//=========================================================================
//=========================================================================
// static
rtl::Reference< TypeDescriptionEnumerationImpl >
TypeDescriptionEnumerationImpl::createInstance(
const uno::Reference< container::XHierarchicalNameAccess > & xTDMgr,
const rtl::OUString & rModuleName,
const uno::Sequence< uno::TypeClass > & rTypes,
reflection::TypeDescriptionSearchDepth eDepth,
const RegistryKeyList & rBaseKeys )
throw ( reflection::NoSuchTypeNameException,
reflection::InvalidTypeNameException,
uno::RuntimeException )
{
if ( rModuleName.getLength() == 0 )
{
// Enumeration for root requested.
return rtl::Reference< TypeDescriptionEnumerationImpl >(
new TypeDescriptionEnumerationImpl(
xTDMgr, rBaseKeys, rTypes, eDepth ) );
}
RegistryKeyList aModuleKeys;
rtl::OUString aKey( rModuleName.replace( '.', '/' ) );
bool bOpenKeySucceeded = false;
const RegistryKeyList::const_iterator end = rBaseKeys.end();
RegistryKeyList::const_iterator it = rBaseKeys.begin();
while ( it != end )
{
uno::Reference< registry::XRegistryKey > xKey;
try
{
xKey = (*it)->openKey( aKey );
if ( xKey.is() )
{
// closes key in it's dtor (which is
// called even in case of exceptions).
RegistryKeyCloser aCloser( xKey );
if ( xKey->isValid() )
{
bOpenKeySucceeded = true;
if ( xKey->getValueType()
== registry::RegistryValueType_BINARY )
{
uno::Sequence< sal_Int8 > aBytes(
xKey->getBinaryValue() );
typereg::Reader aReader(
aBytes.getConstArray(), aBytes.getLength(), false,
TYPEREG_VERSION_1);
rtl::OUString aName(
aReader.getTypeName().replace( '/', '.' ) );
if ( aReader.getTypeClass() == RT_TYPE_MODULE )
{
// Do not close xKey!
aCloser.reset();
aModuleKeys.push_back( xKey );
}
}
}
else
{
OSL_ENSURE(
sal_False,
"TypeDescriptionEnumerationImpl::createInstance "
"- Invalid registry key!" );
}
}
}
catch ( registry::InvalidRegistryException const & )
{
// openKey, getValueType, getBinaryValue
OSL_ENSURE( sal_False,
"TypeDescriptionEnumerationImpl::createInstance "
"- Caught InvalidRegistryException!" );
}
it++;
}
if ( !bOpenKeySucceeded )
throw reflection::NoSuchTypeNameException();
if ( aModuleKeys.size() == 0 )
throw reflection::InvalidTypeNameException();
return rtl::Reference< TypeDescriptionEnumerationImpl >(
new TypeDescriptionEnumerationImpl(
xTDMgr, aModuleKeys, rTypes, eDepth ) );
}
//=========================================================================
TypeDescriptionEnumerationImpl::TypeDescriptionEnumerationImpl(
const uno::Reference< container::XHierarchicalNameAccess > & xTDMgr,
const RegistryKeyList & rModuleKeys,
const uno::Sequence< uno::TypeClass > & rTypes,
reflection::TypeDescriptionSearchDepth eDepth )
: m_aModuleKeys( rModuleKeys ),
m_aTypes( rTypes ),
m_eDepth( eDepth ),
m_xTDMgr( xTDMgr )
{
g_moduleCount.modCnt.acquire( &g_moduleCount.modCnt );
}
//=========================================================================
// virtual
TypeDescriptionEnumerationImpl::~TypeDescriptionEnumerationImpl()
{
RegistryKeyList::const_iterator it = m_aModuleKeys.begin();
RegistryKeyList::const_iterator end = m_aModuleKeys.end();
/*
@@@ in case we enumerate root and queryMore was never called, then
m_aModuleKeys contains open root keys which where passed from
tdprov and must not be closed by us.
while ( it != end )
{
try
{
if ( (*it)->isValid() )
(*it)->closeKey();
}
catch (...)
{
// No exceptions from dtors, please!
OSL_ENSURE( sal_False,
"TypeDescriptionEnumerationImpl::~TypeDescriptionEnumerationImpl "
"- Caught exception!" );
}
it++;
}
*/
it = m_aCurrentModuleSubKeys.begin();
end = m_aCurrentModuleSubKeys.end();
while ( it != end )
{
try
{
if ( (*it)->isValid() )
(*it)->closeKey();
}
catch (Exception &)
{
// No exceptions from dtors, please!
OSL_ENSURE( sal_False,
"TypeDescriptionEnumerationImpl::~TypeDescriptionEnumerationImpl "
"- Caught exception!" );
}
it++;
}
g_moduleCount.modCnt.release( &g_moduleCount.modCnt );
}
//=========================================================================
//
// XEnumeration (base of XTypeDescriptionEnumeration) methods
//
//=========================================================================
// virtual
sal_Bool SAL_CALL TypeDescriptionEnumerationImpl::hasMoreElements()
throw ( uno::RuntimeException )
{
return queryMore();
}
//=========================================================================
// virtual
uno::Any SAL_CALL TypeDescriptionEnumerationImpl::nextElement()
throw ( container::NoSuchElementException,
lang::WrappedTargetException,
uno::RuntimeException )
{
return uno::Any( uno::makeAny( nextTypeDescription() ) );
}
//=========================================================================
//
// XTypeDescriptionEnumeration methods
//
//=========================================================================
// virtual
uno::Reference< reflection::XTypeDescription > SAL_CALL
TypeDescriptionEnumerationImpl::nextTypeDescription()
throw ( container::NoSuchElementException,
uno::RuntimeException )
{
uno::Reference< reflection::XTypeDescription > xTD( queryNext() );
if ( xTD.is() )
return xTD;
throw container::NoSuchElementException(
rtl::OUString::createFromAscii(
"No further elements in enumeration!" ),
static_cast< cppu::OWeakObject * >( this ) );
}
//=========================================================================
bool TypeDescriptionEnumerationImpl::match(
RTTypeClass eType1, uno::TypeClass eType2 )
{
switch ( eType1 )
{
case RT_TYPE_INTERFACE:
return eType2 == uno::TypeClass_INTERFACE;
case RT_TYPE_MODULE:
return eType2 == uno::TypeClass_MODULE;
case RT_TYPE_STRUCT:
return eType2 == uno::TypeClass_STRUCT;
case RT_TYPE_ENUM:
return eType2 == uno::TypeClass_ENUM;
case RT_TYPE_EXCEPTION:
return eType2 == uno::TypeClass_EXCEPTION;
case RT_TYPE_TYPEDEF:
return eType2 == uno::TypeClass_TYPEDEF;
case RT_TYPE_SERVICE:
return eType2 == uno::TypeClass_SERVICE;
case RT_TYPE_SINGLETON:
return eType2 == uno::TypeClass_SINGLETON;
case RT_TYPE_CONSTANTS:
return eType2 == uno::TypeClass_CONSTANTS;
case RT_TYPE_UNION:
return eType2 == uno::TypeClass_UNION;
default:
return false;
}
}
//=========================================================================
bool TypeDescriptionEnumerationImpl::queryMore()
{
osl::MutexGuard aGuard( m_aMutex );
for (;;)
{
if ( !m_aCurrentModuleSubKeys.empty() || !m_aTypeDescs.empty() )
{
// Okay, there is at least one more element.
return true;
}
if ( m_aModuleKeys.empty() )
{
// No module keys (therefore no elements) left.
return false;
}
// Note: m_aCurrentModuleSubKeys is always empty AND m_aModuleKeys is
// never empty when ariving here.
// ==> select new module key, fill m_aCurrentModuleSubKeys
uno::Sequence< uno::Reference< registry::XRegistryKey > > aKeys;
try
{
aKeys = m_aModuleKeys.front()->openKeys();
for ( sal_Int32 n = 0; n < aKeys.getLength(); ++n )
{
uno::Reference< registry::XRegistryKey > xKey = aKeys[ n ];
// closes key in it's dtor (which is
// called even in case of exceptions).
RegistryKeyCloser aCloser( xKey );
try
{
if ( xKey->isValid() )
{
if ( xKey->getValueType()
== registry::RegistryValueType_BINARY )
{
bool bIncludeIt = (m_aTypes.getLength() == 0);
bool bNeedTypeClass =
((m_aTypes.getLength() > 0) ||
(m_eDepth
== reflection::TypeDescriptionSearchDepth_INFINITE));
if ( bNeedTypeClass )
{
uno::Sequence< sal_Int8 > aBytes(
xKey->getBinaryValue() );
typereg::Reader aReader(
aBytes.getConstArray(), aBytes.getLength(),
false, TYPEREG_VERSION_1);
RTTypeClass eTypeClass = aReader.getTypeClass();
// Does key match requested types? Empty
// sequence means include all.
if ( m_aTypes.getLength() > 0 )
{
for ( sal_Int32 m = 0;
m < m_aTypes.getLength();
++m )
{
if ( match(eTypeClass, m_aTypes[ m ]) )
{
bIncludeIt = true;
break;
}
}
}
if ( m_eDepth ==
reflection::TypeDescriptionSearchDepth_INFINITE )
{
if ( eTypeClass == RT_TYPE_MODULE )
{
// Do not close xKey!
aCloser.reset();
// Remember new module key.
m_aModuleKeys.push_back( xKey );
}
}
}
if ( bIncludeIt )
{
// Do not close xKey!
aCloser.reset();
m_aCurrentModuleSubKeys.push_back( xKey );
}
}
}
else
{
OSL_ENSURE( sal_False,
"TypeDescriptionEnumerationImpl::queryMore "
"- Invalid registry key!" );
}
}
catch ( registry::InvalidRegistryException const & )
{
// getValueType, getBinaryValue
OSL_ENSURE( sal_False,
"TypeDescriptionEnumerationImpl::queryMore "
"- Caught InvalidRegistryException!" );
// Don't stop iterating!
}
}
}
catch ( registry::InvalidRegistryException const & )
{
// openKeys
for ( sal_Int32 n = 0; n < aKeys.getLength(); ++n )
{
try
{
aKeys[ n ]->closeKey();
}
catch ( registry::InvalidRegistryException const & )
{
OSL_ENSURE( sal_False,
"TypeDescriptionEnumerationImpl::queryMore "
"- Caught InvalidRegistryException!" );
}
}
}
/////////////////////////////////////////////////////////////////////
// Special handling for constants contained directly in module.
/////////////////////////////////////////////////////////////////////
// Constants requested?
bool bIncludeConstants = ( m_aTypes.getLength() == 0 );
if ( !bIncludeConstants )
{
for ( sal_Int32 m = 0; m < m_aTypes.getLength(); ++m )
{
if ( m_aTypes[ m ] == uno::TypeClass_CONSTANT )
{
bIncludeConstants = true;
break;
}
}
}
if ( bIncludeConstants )
{
if ( m_aModuleKeys.front()->getValueType()
== registry::RegistryValueType_BINARY )
{
try
{
uno::Sequence< sal_Int8 > aBytes(
m_aModuleKeys.front()->getBinaryValue() );
typereg::Reader aReader(
aBytes.getConstArray(), aBytes.getLength(), false,
TYPEREG_VERSION_1);
if ( aReader.getTypeClass() == RT_TYPE_MODULE )
{
sal_uInt16 nFields = aReader.getFieldCount();
while ( nFields-- )
{
rtl::OUStringBuffer aName(
aReader.getTypeName().replace( '/', '.' ) );
aName.appendAscii( "." );
aName.append( aReader.getFieldName( nFields ) );
uno::Any aValue(
getRTValue(
aReader.getFieldValue( nFields ) ) );
m_aTypeDescs.push_back(
new IndividualConstantTypeDescriptionImpl(
aName.makeStringAndClear(), aValue,
( ( aReader.getFieldFlags( nFields )
& RT_ACCESS_PUBLISHED )
!= 0 ) ) );
}
}
}
catch ( registry::InvalidRegistryException const & )
{
// getBinaryValue
OSL_ENSURE( sal_False,
"TypeDescriptionEnumerationImpl::queryMore "
"- Caught InvalidRegistryException!" );
}
}
}
/////////////////////////////////////////////////////////////////////
/*
@@@ m_aModuleKeys.front() may have open sub keys (may be contained in
both m_aModuleKeys and m_aCurrentModuleSubKeys)!
try
{
m_aModuleKeys.front()->closeKey();
}
catch ( registry::InvalidRegistryException const & )
{
OSL_ENSURE( sal_False,
"TypeDescriptionEnumerationImpl::queryMore "
"- Caught InvalidRegistryException!" );
}
*/
// We're done with this module key, even if there were errors.
m_aModuleKeys.pop_front();
}
// unreachable
}
//=========================================================================
uno::Reference< reflection::XTypeDescription >
TypeDescriptionEnumerationImpl::queryNext()
{
osl::MutexGuard aGuard( m_aMutex );
for (;;)
{
if ( !queryMore() )
return uno::Reference< reflection::XTypeDescription >();
uno::Reference< reflection::XTypeDescription > xTD;
if ( !m_aTypeDescs.empty() )
{
xTD = m_aTypeDescs.front();
m_aTypeDescs.pop_front();
return xTD;
}
// Note: xKey is already opened.
uno::Reference< registry::XRegistryKey >
xKey( m_aCurrentModuleSubKeys.front() );
/*
@@@ xKey may still be contained in m_aModuleKeys, too
// closes key in it's dtor (which is
// called even in case of exceptions).
RegistryKeyCloser aCloser( xKey );
*/
try
{
{
if ( xKey->isValid() )
{
if ( xKey->getValueType()
== registry::RegistryValueType_BINARY )
{
uno::Sequence< sal_Int8 > aBytes(
xKey->getBinaryValue() );
xTD = createTypeDescription( aBytes,
m_xTDMgr,
false );
OSL_ENSURE( xTD.is(),
"TypeDescriptionEnumerationImpl::queryNext "
"- No XTypeDescription created!" );
}
}
else
{
OSL_ENSURE( sal_False,
"TypeDescriptionEnumerationImpl::queryNext "
"- Invalid registry key!" );
}
}
}
catch ( registry::InvalidRegistryException const & )
{
// getValueType, getBinaryValue
OSL_ENSURE( sal_False,
"TypeDescriptionEnumerationImpl::queryNext "
"- Caught InvalidRegistryException!" );
}
// We're done with this key, even if there were errors.
m_aCurrentModuleSubKeys.pop_front();
if ( xTD.is() )
return xTD;
// next try...
} // for (;;)
}
} // namespace stoc_rdbtdp