diff options
Diffstat (limited to 'stoc/source/inspect/introspection.cxx')
-rw-r--r-- | stoc/source/inspect/introspection.cxx | 3081 |
1 files changed, 3081 insertions, 0 deletions
diff --git a/stoc/source/inspect/introspection.cxx b/stoc/source/inspect/introspection.cxx new file mode 100644 index 000000000000..b6770e7d2cba --- /dev/null +++ b/stoc/source/inspect/introspection.cxx @@ -0,0 +1,3081 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_stoc.hxx" + +#include <string.h> + +// Schalter fuer Introspection-Caching +#ifndef OS2 +#define USE_INTROSPECTION_CACHE +#endif + +#ifdef USE_INTROSPECTION_CACHE +#define INTROSPECTION_CACHE_MAX_SIZE 100 +#endif +#include <osl/diagnose.h> +#include <osl/mutex.hxx> +#include <osl/thread.h> +#include <cppuhelper/queryinterface.hxx> +#include <cppuhelper/weak.hxx> +#include <cppuhelper/component.hxx> +#include <cppuhelper/factory.hxx> +#include <cppuhelper/implbase3.hxx> +#include <cppuhelper/typeprovider.hxx> + +#include <com/sun/star/uno/DeploymentException.hpp> +#include <com/sun/star/lang/XSingleServiceFactory.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/lang/XEventListener.hpp> +#include <com/sun/star/reflection/XIdlReflection.hpp> +#include <com/sun/star/reflection/XIdlClassProvider.hpp> +#include <com/sun/star/reflection/XIdlClass.hpp> +#include <com/sun/star/reflection/XIdlField2.hpp> +#include <com/sun/star/beans/UnknownPropertyException.hpp> +#include <com/sun/star/beans/Property.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/beans/XFastPropertySet.hpp> +#include <com/sun/star/beans/XIntrospection.hpp> +#include <com/sun/star/beans/XIntrospectionAccess.hpp> +#include <com/sun/star/beans/XMaterialHolder.hpp> +#include <com/sun/star/beans/XExactName.hpp> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/beans/PropertyConcept.hpp> +#include <com/sun/star/beans/MethodConcept.hpp> +#include <com/sun/star/container/XNameContainer.hpp> +#include <com/sun/star/container/XIndexContainer.hpp> +#include <com/sun/star/container/XEnumerationAccess.hpp> + +#include <rtl/ustrbuf.hxx> +#include <rtl/strbuf.hxx> +#include <boost/unordered_map.hpp> + +using namespace com::sun::star::uno; +using namespace com::sun::star::lang; +using namespace com::sun::star::reflection; +using namespace com::sun::star::container; +using namespace com::sun::star::registry; +using namespace com::sun::star::beans; +using namespace com::sun::star::beans::PropertyAttribute; +using namespace com::sun::star::beans::PropertyConcept; +using namespace com::sun::star::beans::MethodConcept; +using namespace cppu; +using namespace osl; + +using ::rtl::OUString; +using ::rtl::OUStringToOString; +using ::rtl::OString; + +#define IMPLEMENTATION_NAME "com.sun.star.comp.stoc.Introspection" +#define SERVICE_NAME "com.sun.star.beans.Introspection" + +namespace stoc_inspect +{ + +typedef WeakImplHelper3< XIntrospectionAccess, XMaterialHolder, XExactName > IntrospectionAccessHelper; + + +//================================================================================================== + +// Spezial-Wert fuer Method-Concept, um "normale" Funktionen kennzeichnen zu koennen +#define MethodConcept_NORMAL_IMPL 0x80000000 + + +// Methode zur Feststellung, ob eine Klasse von einer anderen abgeleitet ist +sal_Bool isDerivedFrom( Reference<XIdlClass> xToTestClass, Reference<XIdlClass> xDerivedFromClass ) +{ + Sequence< Reference<XIdlClass> > aClassesSeq = xToTestClass->getSuperclasses(); + const Reference<XIdlClass>* pClassesArray = aClassesSeq.getConstArray(); + sal_Int32 nSuperClassCount = aClassesSeq.getLength(); + sal_Int32 i; + for( i = 0 ; i < nSuperClassCount ; i++ ) + { + const Reference<XIdlClass>& rxClass = pClassesArray[i]; + if( xDerivedFromClass->equals( rxClass ) ) + { + // Treffer + return sal_True; + } + else + { + // Rekursiv weitersuchen + return isDerivedFrom( rxClass, xDerivedFromClass ); + } + } + return sal_False; +} + +//======================================================================== + +// *** Klassifizierung der Properties (kein enum, um Sequence verwenden zu koennen) *** +// Properties aus einem PropertySet-Interface +#define MAP_PROPERTY_SET 0 +// Properties aus Fields +#define MAP_FIELD 1 +// Properties, die durch get/set-Methoden beschrieben werden +#define MAP_GETSET 2 +// Properties, die nur eine set-Methode haben +#define MAP_SETONLY 3 + + +// Schrittweite, in der die Groesse der Sequences angepasst wird +#define ARRAY_SIZE_STEP 20 + + + +//************************************** +//*** IntrospectionAccessStatic_Impl *** +//************************************** +// Entspricht dem alten IntrospectionAccessImpl, bildet jetzt den statischen +// Anteil des neuen Instanz-bezogenen ImplIntrospectionAccess + +// ACHTUNG !!! Von Hand refcounten !!! + + +// Hashtable fuer die Suche nach Namen +struct hashName_Impl +{ + size_t operator()(const OUString Str) const + { + return (size_t)Str.hashCode(); + } +}; + +struct eqName_Impl +{ + sal_Bool operator()(const OUString Str1, const OUString Str2) const + { + return ( Str1 == Str2 ); + } +}; + +typedef boost::unordered_map +< + OUString, + sal_Int32, + hashName_Impl, + eqName_Impl +> +IntrospectionNameMap; + + +// Hashtable zur Zuordnung der exakten Namen zu den zu Lower-Case +// konvertierten Namen, dient zur Unterst�tzung von XExactName +typedef boost::unordered_map +< + OUString, + OUString, + hashName_Impl, + eqName_Impl +> +LowerToExactNameMap; + + +class ImplIntrospectionAccess; +class IntrospectionAccessStatic_Impl +{ + friend class ImplIntrospection; + friend class ImplIntrospectionAccess; + + // CoreReflection halten + Reference< XIdlReflection > mxCoreReflection; + + // InterfaceSequences, um Zusatz-Infos zu einer Property speichern zu koennen. + // z.B. das Field bei MAP_FIELD, die get/set-Methoden bei MAP_GETSET usw. + Sequence< Reference<XInterface> > aInterfaceSeq1; + Sequence< Reference<XInterface> > aInterfaceSeq2; + + // Hashtables fuer die Namen + IntrospectionNameMap maPropertyNameMap; + IntrospectionNameMap maMethodNameMap; + LowerToExactNameMap maLowerToExactNameMap; + + // Sequence aller Properties, auch zum Liefern aus getProperties() + Sequence<Property> maAllPropertySeq; + + // Mapping der Properties auf Zugriffs-Arten + Sequence<sal_Int16> maMapTypeSeq; + + // Klassifizierung der gefundenen Methoden + Sequence<sal_Int32> maPropertyConceptSeq; + + // Anzahl der Properties + sal_Int32 mnPropCount; + + // Anzahl der Properties, die den jeweiligen Konzepten zugeordnet sind + //sal_Int32 mnDangerousPropCount; + sal_Int32 mnPropertySetPropCount; + sal_Int32 mnAttributePropCount; + sal_Int32 mnMethodPropCount; + + // Flag, ob ein FastPropertySet unterstuetzt wird + sal_Bool mbFastPropSet; + + // Original-Handles eines FastPropertySets + sal_Int32* mpOrgPropertyHandleArray; + + // MethodSequence, die alle Methoden aufnimmt + Sequence< Reference<XIdlMethod> > maAllMethodSeq; + + // Klassifizierung der gefundenen Methoden + Sequence<sal_Int32> maMethodConceptSeq; + + // Anzahl der Methoden + sal_Int32 mnMethCount; + + // Sequence der Listener, die angemeldet werden koennen + Sequence< Type > maSupportedListenerSeq; + + // BaseInit (soll spaeter in der Applikation erfolgen!) + void BaseInit( void ); + + // Hilfs-Methoden zur Groessen-Anpassung der Sequences + void checkPropertyArraysSize + ( + Property*& rpAllPropArray, + sal_Int16*& rpMapTypeArray, + sal_Int32*& rpPropertyConceptArray, + sal_Int32 iNextIndex + ); + void checkInterfaceArraySize( Sequence< Reference<XInterface> >& rSeq, Reference<XInterface>*& rpInterfaceArray, + sal_Int32 iNextIndex ); + + // RefCount + sal_Int32 nRefCount; + + +public: + IntrospectionAccessStatic_Impl( Reference< XIdlReflection > xCoreReflection_ ); + ~IntrospectionAccessStatic_Impl() + { + delete[] mpOrgPropertyHandleArray; + } + sal_Int32 getPropertyIndex( const OUString& aPropertyName ) const; + sal_Int32 getMethodIndex( const OUString& aMethodName ) const; + + void acquire() { nRefCount++; } + void release() + { + nRefCount--; + if( nRefCount <= 0 ) + delete this; + } + + // Methoden von XIntrospectionAccess (ALT, jetzt nur Impl) + void setPropertyValue(const Any& obj, const OUString& aPropertyName, const Any& aValue) const; +// void setPropertyValue(Any& obj, const OUString& aPropertyName, const Any& aValue) const; + Any getPropertyValue(const Any& obj, const OUString& aPropertyName) const; + void setPropertyValueByIndex(const Any& obj, sal_Int32 nIndex, const Any& aValue) const; +// void setPropertyValueByIndex(Any& obj, sal_Int32 nIndex, const Any& aValue) const; + Any getPropertyValueByIndex(const Any& obj, sal_Int32 nIndex) const; + + Sequence<Property> getProperties(void) const { return maAllPropertySeq; } + Sequence< Reference<XIdlMethod> > getMethods(void) const { return maAllMethodSeq; } + Sequence< Type > getSupportedListeners(void) const { return maSupportedListenerSeq; } + Sequence<sal_Int32> getPropertyConcepts(void) const { return maPropertyConceptSeq; } + Sequence<sal_Int32> getMethodConcepts(void) const { return maMethodConceptSeq; } +}; + + +// Ctor +IntrospectionAccessStatic_Impl::IntrospectionAccessStatic_Impl( Reference< XIdlReflection > xCoreReflection_ ) + : mxCoreReflection( xCoreReflection_ ) +{ + aInterfaceSeq1.realloc( ARRAY_SIZE_STEP ); + aInterfaceSeq2.realloc( ARRAY_SIZE_STEP ); + + // Property-Daten + maAllPropertySeq.realloc( ARRAY_SIZE_STEP ); + maMapTypeSeq.realloc( ARRAY_SIZE_STEP ); + maPropertyConceptSeq.realloc( ARRAY_SIZE_STEP ); + + mbFastPropSet = sal_False; + mpOrgPropertyHandleArray = NULL; + + mnPropCount = 0; + //mnDangerousPropCount = 0; + mnPropertySetPropCount = 0; + mnAttributePropCount = 0; + mnMethodPropCount = 0; + + // Method-Daten + mnMethCount = 0; + + // Eigenens RefCounting + nRefCount = 0; +} + +// Von Hand refcounten !!! + + +sal_Int32 IntrospectionAccessStatic_Impl::getPropertyIndex( const OUString& aPropertyName ) const +{ + sal_Int32 iHashResult = -1; + IntrospectionAccessStatic_Impl* pThis = (IntrospectionAccessStatic_Impl*)this; + IntrospectionNameMap::iterator aIt = pThis->maPropertyNameMap.find( aPropertyName ); + if( !( aIt == pThis->maPropertyNameMap.end() ) ) + iHashResult = (*aIt).second; + return iHashResult; +} + +sal_Int32 IntrospectionAccessStatic_Impl::getMethodIndex( const OUString& aMethodName ) const +{ + sal_Int32 iHashResult = -1; + IntrospectionAccessStatic_Impl* pThis = (IntrospectionAccessStatic_Impl*)this; + IntrospectionNameMap::iterator aIt = pThis->maMethodNameMap.find( aMethodName ); + if( !( aIt == pThis->maMethodNameMap.end() ) ) + { + iHashResult = (*aIt).second; + } + // #95159 Check if full qualified name matches + else + { + sal_Int32 nSearchFrom = aMethodName.getLength(); + nSearchFrom = aMethodName.getLength(); + while( true ) + { + // Strategy: Search back until the first '_' is found + sal_Int32 nFound = aMethodName.lastIndexOf( '_', nSearchFrom ); + if( nFound == -1 ) + break; + + OUString aPureMethodName = aMethodName.copy( nFound + 1 ); + + aIt = pThis->maMethodNameMap.find( aPureMethodName ); + if( !( aIt == pThis->maMethodNameMap.end() ) ) + { + // Check if it can be a type? + // Problem: Does not work if package names contain _ ?! + OUString aStr = aMethodName.copy( 0, nFound ); + OUString aTypeName = aStr.replace( '_', '.' ); + Reference< XIdlClass > xClass = mxCoreReflection->forName( aTypeName ); + if( xClass.is() ) + { + // If this is a valid class it could be the right method + + // Could be the right method, type has to be checked + iHashResult = (*aIt).second; + + const Reference<XIdlMethod>* pMethods = maAllMethodSeq.getConstArray(); + const Reference<XIdlMethod> xMethod = pMethods[ iHashResult ]; + + Reference< XIdlClass > xMethClass = xMethod->getDeclaringClass(); + if( xClass->equals( xMethClass ) ) + { + break; + } + else + { + iHashResult = -1; + + // Could also be another method with the same name + // Iterate over all methods + sal_Int32 nLen = maAllMethodSeq.getLength(); + for( int i = 0 ; i < nLen ; ++i ) + { + const Reference<XIdlMethod> xMethod2 = pMethods[ i ]; + + OUString aTestClassName = xMethod2->getDeclaringClass()->getName(); + OUString aTestMethodName = xMethod2->getName(); + + if( xMethod2->getName() == aPureMethodName ) + { + Reference< XIdlClass > xMethClass2 = xMethod2->getDeclaringClass(); + + if( xClass->equals( xMethClass2 ) ) + { + iHashResult = i; + break; + } + } + } + + if( iHashResult != -1 ) + break; + } + } + } + + nSearchFrom = nFound - 1; + if( nSearchFrom < 0 ) + break; + } + } + return iHashResult; +} + +void IntrospectionAccessStatic_Impl::setPropertyValue( const Any& obj, const OUString& aPropertyName, const Any& aValue ) const +//void IntrospectionAccessStatic_Impl::setPropertyValue( Any& obj, const OUString& aPropertyName, const Any& aValue ) const +{ + sal_Int32 i = getPropertyIndex( aPropertyName ); + if( i != -1 ) + setPropertyValueByIndex( obj, (sal_Int32)i, aValue ); + else + throw UnknownPropertyException(); +} + +void IntrospectionAccessStatic_Impl::setPropertyValueByIndex(const Any& obj, sal_Int32 nSequenceIndex, const Any& aValue) const +//void IntrospectionAccessStatic_Impl::setPropertyValueByIndex( Any& obj, sal_Int32 nSequenceIndex, const Any& aValue) const +{ + // Handelt es sich bei dem uebergebenen Objekt ueberhaupt um was passendes? + TypeClass eObjType = obj.getValueType().getTypeClass(); + + Reference<XInterface> xInterface; + if( eObjType == TypeClass_INTERFACE ) + { + xInterface = *( Reference<XInterface>*)obj.getValue(); + } + else if( nSequenceIndex >= mnPropCount || ( eObjType != TypeClass_STRUCT && eObjType != TypeClass_EXCEPTION ) ) + { + throw IllegalArgumentException(); + } + + // Flags pruefen + const Property* pProps = maAllPropertySeq.getConstArray(); + if( (pProps[ nSequenceIndex ].Attributes & READONLY) != 0 ) + { + throw UnknownPropertyException(); + } + + const sal_Int16* pMapTypeArray = maMapTypeSeq.getConstArray(); + switch( pMapTypeArray[ nSequenceIndex ] ) + { + case MAP_PROPERTY_SET: + { + // Property besorgen + const Property& rProp = maAllPropertySeq.getConstArray()[ nSequenceIndex ]; + + // Interface-Parameter auf den richtigen Typ bringen + sal_Bool bUseCopy = sal_False; + Any aRealValue; + + TypeClass eValType = aValue.getValueType().getTypeClass(); + if( eValType == TypeClass_INTERFACE ) + { + Type aPropType = rProp.Type; + OUString aTypeName( aPropType.getTypeName() ); + Reference< XIdlClass > xPropClass = mxCoreReflection->forName( aTypeName ); + //Reference<XIdlClass> xPropClass = rProp.Type; + if( xPropClass.is() && xPropClass->getTypeClass() == TypeClass_INTERFACE ) + { + Reference<XInterface> valInterface = *(Reference<XInterface>*)aValue.getValue(); + if( valInterface.is() ) + { + //Any queryInterface( const Type& rType ); + aRealValue = valInterface->queryInterface( aPropType ); + if( aRealValue.hasValue() ) + bUseCopy = sal_True; + } + } + } + + // Haben wir ein FastPropertySet und ein gueltiges Handle? + // ACHTUNG: An dieser Stelle wird ausgenutzt, dass das PropertySet + // zu Beginn des Introspection-Vorgangs abgefragt wird. + sal_Int32 nOrgHandle; + if( mbFastPropSet && ( nOrgHandle = mpOrgPropertyHandleArray[ nSequenceIndex ] ) != -1 ) + { + // PropertySet-Interface holen + Reference<XFastPropertySet> xFastPropSet = + Reference<XFastPropertySet>::query( xInterface ); + if( xFastPropSet.is() ) + { + xFastPropSet->setFastPropertyValue( nOrgHandle, bUseCopy ? aRealValue : aValue ); + } + else + { + // throw UnknownPropertyException + } + } + // sonst eben das normale nehmen + else + { + // PropertySet-Interface holen + Reference<XPropertySet> xPropSet = + Reference<XPropertySet>::query( xInterface ); + if( xPropSet.is() ) + { + xPropSet->setPropertyValue( rProp.Name, bUseCopy ? aRealValue : aValue ); + } + else + { + // throw UnknownPropertyException + } + } + } + break; + + case MAP_FIELD: + { + Reference<XIdlField> xField = (XIdlField*)(aInterfaceSeq1.getConstArray()[ nSequenceIndex ].get()); + Reference<XIdlField2> xField2(xField, UNO_QUERY); + if( xField2.is() ) + { + xField2->set( (Any&)obj, aValue ); + // IllegalArgumentException + // NullPointerException + } else + if( xField.is() ) + { + xField->set( obj, aValue ); + // IllegalArgumentException + // NullPointerException + } + else + { + // throw IllegalArgumentException(); + } + } + break; + + case MAP_GETSET: + case MAP_SETONLY: + { + // set-Methode holen + Reference<XIdlMethod> xMethod = (XIdlMethod*)(aInterfaceSeq2.getConstArray()[ nSequenceIndex ].get()); + if( xMethod.is() ) + { + Sequence<Any> args( 1 ); + args.getArray()[0] = aValue; + xMethod->invoke( obj, args ); + } + else + { + // throw IllegalArgumentException(); + } + } + break; + } +} + +Any IntrospectionAccessStatic_Impl::getPropertyValue( const Any& obj, const OUString& aPropertyName ) const +{ + sal_Int32 i = getPropertyIndex( aPropertyName ); + if( i != -1 ) + return getPropertyValueByIndex( obj, i ); + + throw UnknownPropertyException(); +} + +Any IntrospectionAccessStatic_Impl::getPropertyValueByIndex(const Any& obj, sal_Int32 nSequenceIndex) const +{ + Any aRet; + + // Handelt es sich bei dem uebergebenen Objekt ueberhaupt um was passendes? + TypeClass eObjType = obj.getValueType().getTypeClass(); + + Reference<XInterface> xInterface; + if( eObjType == TypeClass_INTERFACE ) + { + xInterface = *(Reference<XInterface>*)obj.getValue(); + } + else if( nSequenceIndex >= mnPropCount || ( eObjType != TypeClass_STRUCT && eObjType != TypeClass_EXCEPTION ) ) + { + // throw IllegalArgumentException(); + return aRet; + } + + const sal_Int16* pMapTypeArray = maMapTypeSeq.getConstArray(); + switch( pMapTypeArray[ nSequenceIndex ] ) + { + case MAP_PROPERTY_SET: + { + // Property besorgen + const Property& rProp = maAllPropertySeq.getConstArray()[ nSequenceIndex ]; + + // Haben wir ein FastPropertySet und ein gueltiges Handle? + // ACHTUNG: An dieser Stelle wird ausgenutzt, dass das PropertySet + // zu Beginn des Introspection-Vorgangs abgefragt wird. + sal_Int32 nOrgHandle; + if( mbFastPropSet && ( nOrgHandle = mpOrgPropertyHandleArray[ nSequenceIndex ] ) != -1 ) + { + // PropertySet-Interface holen + Reference<XFastPropertySet> xFastPropSet = + Reference<XFastPropertySet>::query( xInterface ); + if( xFastPropSet.is() ) + { + aRet = xFastPropSet->getFastPropertyValue( nOrgHandle); + } + else + { + // throw UnknownPropertyException + return aRet; + } + } + // sonst eben das normale nehmen + else + { + // PropertySet-Interface holen + Reference<XPropertySet> xPropSet = + Reference<XPropertySet>::query( xInterface ); + if( xPropSet.is() ) + { + aRet = xPropSet->getPropertyValue( rProp.Name ); + } + else + { + // throw UnknownPropertyException + return aRet; + } + } + } + break; + + case MAP_FIELD: + { + Reference<XIdlField> xField = (XIdlField*)(aInterfaceSeq1.getConstArray()[ nSequenceIndex ].get()); + if( xField.is() ) + { + aRet = xField->get( obj ); + // IllegalArgumentException + // NullPointerException + } + else + { + // throw IllegalArgumentException(); + return aRet; + } + } + break; + + case MAP_GETSET: + { + // get-Methode holen + Reference<XIdlMethod> xMethod = (XIdlMethod*)(aInterfaceSeq1.getConstArray()[ nSequenceIndex ].get()); + if( xMethod.is() ) + { + Sequence<Any> args; + aRet = xMethod->invoke( obj, args ); + } + else + { + // throw IllegalArgumentException(); + return aRet; + } + } + break; + + case MAP_SETONLY: + // get-Methode gibt es nicht + // throw WriteOnlyPropertyException(); + return aRet; + } + return aRet; +} + + +// Hilfs-Methoden zur Groessen-Anpassung der Sequences +void IntrospectionAccessStatic_Impl::checkPropertyArraysSize +( + Property*& rpAllPropArray, + sal_Int16*& rpMapTypeArray, + sal_Int32*& rpPropertyConceptArray, + sal_Int32 iNextIndex +) +{ + sal_Int32 nLen = maAllPropertySeq.getLength(); + if( iNextIndex >= nLen ) + { + maAllPropertySeq.realloc( nLen + ARRAY_SIZE_STEP ); + rpAllPropArray = maAllPropertySeq.getArray(); + + maMapTypeSeq.realloc( nLen + ARRAY_SIZE_STEP ); + rpMapTypeArray = maMapTypeSeq.getArray(); + + maPropertyConceptSeq.realloc( nLen + ARRAY_SIZE_STEP ); + rpPropertyConceptArray = maPropertyConceptSeq.getArray(); + } +} + +void IntrospectionAccessStatic_Impl::checkInterfaceArraySize( Sequence< Reference<XInterface> >& rSeq, + Reference<XInterface>*& rpInterfaceArray, sal_Int32 iNextIndex ) +{ + sal_Int32 nLen = rSeq.getLength(); + if( iNextIndex >= nLen ) + { + // Neue Groesse mit ARRAY_SIZE_STEP abgleichen + sal_Int32 nMissingSize = iNextIndex - nLen + 1; + sal_Int32 nSteps = nMissingSize / ARRAY_SIZE_STEP + 1; + sal_Int32 nNewSize = nLen + nSteps * ARRAY_SIZE_STEP; + + rSeq.realloc( nNewSize ); + rpInterfaceArray = rSeq.getArray(); + } +} + + +//******************************* +//*** ImplIntrospectionAdapter *** +//******************************* + +// Neue Impl-Klasse im Rahmen der Introspection-Umstellung auf Instanz-gebundene +// Introspection mit Property-Zugriff ueber XPropertySet. Die alte Klasse +// ImplIntrospectionAccess lebt als IntrospectionAccessStatic_Impl +class ImplIntrospectionAdapter : + public XPropertySet, public XFastPropertySet, public XPropertySetInfo, + public XNameContainer, public XIndexContainer, + public XEnumerationAccess, public XIdlArray, + public OWeakObject +{ + // Parent-Objekt + ImplIntrospectionAccess* mpAccess; + + // Untersuchtes Objekt + const Any& mrInspectedObject; + + // Statische Daten der Introspection + IntrospectionAccessStatic_Impl* mpStaticImpl; + + // Objekt als Interface + Reference<XInterface> mxIface; + + // Original-Interfaces des Objekts + Reference<XElementAccess> mxObjElementAccess; + Reference<XNameContainer> mxObjNameContainer; + Reference<XNameAccess> mxObjNameAccess; + Reference<XIndexAccess> mxObjIndexAccess; + Reference<XIndexContainer> mxObjIndexContainer; + Reference<XEnumerationAccess> mxObjEnumerationAccess; + Reference<XIdlArray> mxObjIdlArray; + +public: + ImplIntrospectionAdapter( ImplIntrospectionAccess* pAccess_, + const Any& obj, IntrospectionAccessStatic_Impl* pStaticImpl_ ); + ~ImplIntrospectionAdapter(); + + // Methoden von XInterface + virtual Any SAL_CALL queryInterface( const Type& rType ) throw( RuntimeException ); + virtual void SAL_CALL acquire() throw() { OWeakObject::acquire(); } + virtual void SAL_CALL release() throw() { OWeakObject::release(); } + + // Methoden von XPropertySet + virtual Reference<XPropertySetInfo> SAL_CALL getPropertySetInfo() throw( RuntimeException ); + virtual void SAL_CALL setPropertyValue(const OUString& aPropertyName, const Any& aValue) + throw( UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException ); + virtual Any SAL_CALL getPropertyValue(const OUString& aPropertyName) + throw( UnknownPropertyException, WrappedTargetException, RuntimeException ); + virtual void SAL_CALL addPropertyChangeListener(const OUString& aPropertyName, const Reference<XPropertyChangeListener>& aListener) + throw( UnknownPropertyException, WrappedTargetException, RuntimeException ); + virtual void SAL_CALL removePropertyChangeListener(const OUString& aPropertyName, const Reference<XPropertyChangeListener>& aListener) + throw( UnknownPropertyException, WrappedTargetException, RuntimeException ); + virtual void SAL_CALL addVetoableChangeListener(const OUString& aPropertyName, const Reference<XVetoableChangeListener>& aListener) + throw( UnknownPropertyException, WrappedTargetException, RuntimeException ); + virtual void SAL_CALL removeVetoableChangeListener(const OUString& aPropertyName, const Reference<XVetoableChangeListener>& aListener) + throw( UnknownPropertyException, WrappedTargetException, RuntimeException ); + + // Methoden von XFastPropertySet + virtual void SAL_CALL setFastPropertyValue(sal_Int32 nHandle, const Any& aValue) + throw( UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException ); + virtual Any SAL_CALL getFastPropertyValue(sal_Int32 nHandle) + throw( UnknownPropertyException, WrappedTargetException, RuntimeException ); + + // Methoden von XPropertySetInfo + virtual Sequence< Property > SAL_CALL getProperties(void) throw( RuntimeException ); + virtual Property SAL_CALL getPropertyByName(const OUString& Name) throw( RuntimeException ); + virtual sal_Bool SAL_CALL hasPropertyByName(const OUString& Name) throw( RuntimeException ); + + // Methoden von XElementAccess + virtual Type SAL_CALL getElementType(void) throw( RuntimeException ); + virtual sal_Bool SAL_CALL hasElements(void) throw( RuntimeException ); + + // Methoden von XNameAccess + virtual Any SAL_CALL getByName(const OUString& Name) + throw( NoSuchElementException, WrappedTargetException, RuntimeException ); + virtual Sequence<OUString> SAL_CALL getElementNames(void) throw( RuntimeException ); + virtual sal_Bool SAL_CALL hasByName(const OUString& Name) throw( RuntimeException ); + + // Methoden von XNameContainer + virtual void SAL_CALL insertByName(const OUString& Name, const Any& Element) + throw( IllegalArgumentException, ElementExistException, WrappedTargetException, RuntimeException ); + virtual void SAL_CALL replaceByName(const OUString& Name, const Any& Element) + throw( IllegalArgumentException, NoSuchElementException, WrappedTargetException, RuntimeException ); + virtual void SAL_CALL removeByName(const OUString& Name) + throw( NoSuchElementException, WrappedTargetException, RuntimeException ); + + // Methoden von XIndexAccess + virtual sal_Int32 SAL_CALL getCount(void) throw( RuntimeException ); + virtual Any SAL_CALL getByIndex(sal_Int32 Index) + throw( IndexOutOfBoundsException, WrappedTargetException, RuntimeException ); + + // Methoden von XIndexContainer + virtual void SAL_CALL insertByIndex(sal_Int32 Index, const Any& Element) + throw( IllegalArgumentException, IndexOutOfBoundsException, WrappedTargetException, RuntimeException ); + virtual void SAL_CALL replaceByIndex(sal_Int32 Index, const Any& Element) + throw( IllegalArgumentException, IndexOutOfBoundsException, WrappedTargetException, RuntimeException ); + virtual void SAL_CALL removeByIndex(sal_Int32 Index) + throw( IndexOutOfBoundsException, WrappedTargetException, RuntimeException ); + + // Methoden von XEnumerationAccess + virtual Reference<XEnumeration> SAL_CALL createEnumeration(void) throw( RuntimeException ); + + // Methoden von XIdlArray + virtual void SAL_CALL realloc(Any& array, sal_Int32 length) + throw( IllegalArgumentException, RuntimeException ); + virtual sal_Int32 SAL_CALL getLen(const Any& array) throw( IllegalArgumentException, RuntimeException ); + virtual Any SAL_CALL get(const Any& array, sal_Int32 index) + throw( IllegalArgumentException, ArrayIndexOutOfBoundsException, RuntimeException ); + virtual void SAL_CALL set(Any& array, sal_Int32 index, const Any& value) + throw( IllegalArgumentException, ArrayIndexOutOfBoundsException, RuntimeException ); +}; + +ImplIntrospectionAdapter::ImplIntrospectionAdapter( ImplIntrospectionAccess* pAccess_, + const Any& obj, IntrospectionAccessStatic_Impl* pStaticImpl_ ) + : mpAccess( pAccess_), mrInspectedObject( obj ), mpStaticImpl( pStaticImpl_ ) +{ + mpStaticImpl->acquire(); + + // Objekt als Interfaceholen + TypeClass eType = mrInspectedObject.getValueType().getTypeClass(); + if( eType == TypeClass_INTERFACE ) + { + mxIface = *( Reference< XInterface >*)mrInspectedObject.getValue(); + + mxObjElementAccess = Reference<XElementAccess>::query( mxIface ); + mxObjNameAccess = Reference<XNameAccess>::query( mxIface ); + mxObjNameContainer = Reference<XNameContainer>::query( mxIface ); + mxObjIndexAccess = Reference<XIndexAccess>::query( mxIface ); + mxObjIndexContainer = Reference<XIndexContainer>::query( mxIface ); + mxObjEnumerationAccess = Reference<XEnumerationAccess>::query( mxIface ); + mxObjIdlArray = Reference<XIdlArray>::query( mxIface ); + } +} + +ImplIntrospectionAdapter::~ImplIntrospectionAdapter() +{ + mpStaticImpl->release(); +} + +// Methoden von XInterface +Any SAL_CALL ImplIntrospectionAdapter::queryInterface( const Type& rType ) + throw( RuntimeException ) +{ + Any aRet( ::cppu::queryInterface( + rType, + static_cast< XPropertySet * >( this ), + static_cast< XFastPropertySet * >( this ), + static_cast< XPropertySetInfo * >( this ) ) ); + if( !aRet.hasValue() ) + aRet = OWeakObject::queryInterface( rType ); + + if( !aRet.hasValue() ) + { + // Wrapper fuer die Objekt-Interfaces + if( ( mxObjElementAccess.is() && (aRet = ::cppu::queryInterface + ( rType, static_cast< XElementAccess* >( static_cast< XNameAccess* >( this ) ) ) ).hasValue() ) + || ( mxObjNameAccess.is() && (aRet = ::cppu::queryInterface( rType, static_cast< XNameAccess* >( this ) ) ).hasValue() ) + || ( mxObjNameContainer.is() && (aRet = ::cppu::queryInterface( rType, static_cast< XNameContainer* >( this ) ) ).hasValue() ) + || ( mxObjIndexAccess.is() && (aRet = ::cppu::queryInterface( rType, static_cast< XIndexAccess* >( this ) ) ).hasValue() ) + || ( mxObjIndexContainer.is() && (aRet = ::cppu::queryInterface( rType, static_cast< XIndexContainer* >( this ) ) ).hasValue() ) + || ( mxObjEnumerationAccess .is() && (aRet = ::cppu::queryInterface( rType, static_cast< XEnumerationAccess* >( this ) ) ).hasValue() ) + || ( mxObjIdlArray.is() && (aRet = ::cppu::queryInterface( rType, static_cast< XIdlArray* >( this ) ) ).hasValue() ) + ) + { + } + } + return aRet; +} + + +//******************************* +//*** ImplIntrospectionAccess *** +//******************************* + +// Neue Impl-Klasse im Rahmen der Introspection-Umstellung auf Instanz-gebundene +// Introspection mit Property-Zugriff ueber XPropertySet. Die alte Klasse +// ImplIntrospectionAccess lebt als IntrospectionAccessStatic_Impl +class ImplIntrospectionAccess : IntrospectionAccessHelper +{ + friend class ImplIntrospection; + + // Untersuchtes Objekt + Any maInspectedObject; + + // Als Interface + Reference<XInterface> mxIface; + + // Statische Daten der Introspection + IntrospectionAccessStatic_Impl* mpStaticImpl; + + // Adapter-Implementation + ImplIntrospectionAdapter* mpAdapter; + + // Letzte Sequence, die bei getProperties geliefert wurde (Optimierung) + Sequence<Property> maLastPropertySeq; + sal_Int32 mnLastPropertyConcept; + + // Letzte Sequence, die bei getMethods geliefert wurde (Optimierung) + Sequence<Reference<XIdlMethod> > maLastMethodSeq; + sal_Int32 mnLastMethodConcept; + +public: + ImplIntrospectionAccess( const Any& obj, IntrospectionAccessStatic_Impl* pStaticImpl_ ); + ~ImplIntrospectionAccess(); + + // Methoden von XIntrospectionAccess + virtual sal_Int32 SAL_CALL getSuppliedMethodConcepts(void) + throw( RuntimeException ); + virtual sal_Int32 SAL_CALL getSuppliedPropertyConcepts(void) + throw( RuntimeException ); + virtual Property SAL_CALL getProperty(const OUString& Name, sal_Int32 PropertyConcepts) + throw( NoSuchElementException, RuntimeException ); + virtual sal_Bool SAL_CALL hasProperty(const OUString& Name, sal_Int32 PropertyConcepts) + throw( RuntimeException ); + virtual Sequence< Property > SAL_CALL getProperties(sal_Int32 PropertyConcepts) + throw( RuntimeException ); + virtual Reference<XIdlMethod> SAL_CALL getMethod(const OUString& Name, sal_Int32 MethodConcepts) + throw( NoSuchMethodException, RuntimeException ); + virtual sal_Bool SAL_CALL hasMethod(const OUString& Name, sal_Int32 MethodConcepts) + throw( RuntimeException ); + virtual Sequence< Reference<XIdlMethod> > SAL_CALL getMethods(sal_Int32 MethodConcepts) + throw( RuntimeException ); + virtual Sequence< Type > SAL_CALL getSupportedListeners(void) + throw( RuntimeException ); + using OWeakObject::queryAdapter; + virtual Reference<XInterface> SAL_CALL queryAdapter( const Type& rType ) + throw( IllegalTypeException, RuntimeException ); + + // Methoden von XMaterialHolder + virtual Any SAL_CALL getMaterial(void) throw(RuntimeException); + + // Methoden von XExactName + virtual OUString SAL_CALL getExactName( const OUString& rApproximateName ) throw( RuntimeException ); +}; + +ImplIntrospectionAccess::ImplIntrospectionAccess + ( const Any& obj, IntrospectionAccessStatic_Impl* pStaticImpl_ ) + : maInspectedObject( obj ), mpStaticImpl( pStaticImpl_ ), mpAdapter( NULL ) +{ + mpStaticImpl->acquire(); + + // Objekt als Interface merken, wenn moeglich + TypeClass eType = maInspectedObject.getValueType().getTypeClass(); + if( eType == TypeClass_INTERFACE ) + mxIface = *(Reference<XInterface>*)maInspectedObject.getValue(); + + mnLastPropertyConcept = -1; + mnLastMethodConcept = -1; +} + +ImplIntrospectionAccess::~ImplIntrospectionAccess() +{ + mpStaticImpl->release(); + + // Eigene Referenz loslassen + if (mpAdapter) + mpAdapter->release(); +} + + +//*************************************************** +//*** Implementation von ImplIntrospectionAdapter *** +//*************************************************** + +// Methoden von XPropertySet +Reference<XPropertySetInfo> ImplIntrospectionAdapter::getPropertySetInfo(void) + throw( RuntimeException ) +{ + return (XPropertySetInfo *)this; +} + +void ImplIntrospectionAdapter::setPropertyValue(const OUString& aPropertyName, const Any& aValue) + throw( UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException ) +{ + mpStaticImpl->setPropertyValue( mrInspectedObject, aPropertyName, aValue ); +} + +Any ImplIntrospectionAdapter::getPropertyValue(const OUString& aPropertyName) + throw( UnknownPropertyException, WrappedTargetException, RuntimeException ) +{ + return mpStaticImpl->getPropertyValue( mrInspectedObject, aPropertyName ); +} + +void ImplIntrospectionAdapter::addPropertyChangeListener(const OUString& aPropertyName, const Reference<XPropertyChangeListener>& aListener) + throw( UnknownPropertyException, WrappedTargetException, RuntimeException ) +{ + if( mxIface.is() ) + { + Reference<XPropertySet> xPropSet = + Reference<XPropertySet>::query( mxIface ); + //Reference<XPropertySet> xPropSet( mxIface, USR_QUERY ); + if( xPropSet.is() ) + xPropSet->addPropertyChangeListener(aPropertyName, aListener); + } +} + +void ImplIntrospectionAdapter::removePropertyChangeListener(const OUString& aPropertyName, const Reference<XPropertyChangeListener>& aListener) + throw( UnknownPropertyException, WrappedTargetException, RuntimeException ) +{ + if( mxIface.is() ) + { + Reference<XPropertySet> xPropSet = + Reference<XPropertySet>::query( mxIface ); + //Reference<XPropertySet> xPropSet( mxIface, USR_QUERY ); + if( xPropSet.is() ) + xPropSet->removePropertyChangeListener(aPropertyName, aListener); + } +} + +void ImplIntrospectionAdapter::addVetoableChangeListener(const OUString& aPropertyName, const Reference<XVetoableChangeListener>& aListener) + throw( UnknownPropertyException, WrappedTargetException, RuntimeException ) +{ + if( mxIface.is() ) + { + Reference<XPropertySet> xPropSet = + Reference<XPropertySet>::query( mxIface ); + //Reference<XPropertySet> xPropSet( mxIface, USR_QUERY ); + if( xPropSet.is() ) + xPropSet->addVetoableChangeListener(aPropertyName, aListener); + } +} + +void ImplIntrospectionAdapter::removeVetoableChangeListener(const OUString& aPropertyName, const Reference<XVetoableChangeListener>& aListener) + throw( UnknownPropertyException, WrappedTargetException, RuntimeException ) +{ + if( mxIface.is() ) + { + Reference<XPropertySet> xPropSet = + Reference<XPropertySet>::query( mxIface ); + if( xPropSet.is() ) + xPropSet->removeVetoableChangeListener(aPropertyName, aListener); + } +} + + +// Methoden von XFastPropertySet +void ImplIntrospectionAdapter::setFastPropertyValue(sal_Int32, const Any&) + throw( UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException ) +{ +} + +Any ImplIntrospectionAdapter::getFastPropertyValue(sal_Int32) + throw( UnknownPropertyException, WrappedTargetException, RuntimeException ) +{ + return Any(); +} + +// Methoden von XPropertySetInfo +Sequence< Property > ImplIntrospectionAdapter::getProperties(void) throw( RuntimeException ) +{ + return mpStaticImpl->getProperties(); +} + +Property ImplIntrospectionAdapter::getPropertyByName(const OUString& Name) + throw( RuntimeException ) +{ + return mpAccess->getProperty( Name, PropertyConcept::ALL ); +} + +sal_Bool ImplIntrospectionAdapter::hasPropertyByName(const OUString& Name) + throw( RuntimeException ) +{ + return mpAccess->hasProperty( Name, PropertyConcept::ALL ); +} + +// Methoden von XElementAccess +Type ImplIntrospectionAdapter::getElementType(void) throw( RuntimeException ) +{ + return mxObjElementAccess->getElementType(); +} + +sal_Bool ImplIntrospectionAdapter::hasElements(void) throw( RuntimeException ) +{ + return mxObjElementAccess->hasElements(); +} + +// Methoden von XNameAccess +Any ImplIntrospectionAdapter::getByName(const OUString& Name) + throw( NoSuchElementException, WrappedTargetException, RuntimeException ) +{ + return mxObjNameAccess->getByName( Name ); +} + +Sequence< OUString > ImplIntrospectionAdapter::getElementNames(void) + throw( RuntimeException ) +{ + return mxObjNameAccess->getElementNames(); +} + +sal_Bool ImplIntrospectionAdapter::hasByName(const OUString& Name) + throw( RuntimeException ) +{ + return mxObjNameAccess->hasByName( Name ); +} + +// Methoden von XNameContainer +void ImplIntrospectionAdapter::insertByName(const OUString& Name, const Any& Element) + throw( IllegalArgumentException, ElementExistException, WrappedTargetException, RuntimeException ) +{ + mxObjNameContainer->insertByName( Name, Element ); +} + +void ImplIntrospectionAdapter::replaceByName(const OUString& Name, const Any& Element) + throw( IllegalArgumentException, NoSuchElementException, WrappedTargetException, RuntimeException ) +{ + mxObjNameContainer->replaceByName( Name, Element ); +} + +void ImplIntrospectionAdapter::removeByName(const OUString& Name) + throw( NoSuchElementException, WrappedTargetException, RuntimeException ) +{ + mxObjNameContainer->removeByName( Name ); +} + +// Methoden von XIndexAccess +// Schon in XNameAccess: virtual Reference<XIdlClass> getElementType(void) const +sal_Int32 ImplIntrospectionAdapter::getCount(void) throw( RuntimeException ) +{ + return mxObjIndexAccess->getCount(); +} + +Any ImplIntrospectionAdapter::getByIndex(sal_Int32 Index) + throw( IndexOutOfBoundsException, WrappedTargetException, RuntimeException ) +{ + return mxObjIndexAccess->getByIndex( Index ); +} + +// Methoden von XIndexContainer +void ImplIntrospectionAdapter::insertByIndex(sal_Int32 Index, const Any& Element) + throw( IllegalArgumentException, IndexOutOfBoundsException, WrappedTargetException, RuntimeException ) +{ + mxObjIndexContainer->insertByIndex( Index, Element ); +} + +void ImplIntrospectionAdapter::replaceByIndex(sal_Int32 Index, const Any& Element) + throw( IllegalArgumentException, IndexOutOfBoundsException, WrappedTargetException, RuntimeException ) +{ + mxObjIndexContainer->replaceByIndex( Index, Element ); +} + +void ImplIntrospectionAdapter::removeByIndex(sal_Int32 Index) + throw( IndexOutOfBoundsException, WrappedTargetException, RuntimeException ) +{ + mxObjIndexContainer->removeByIndex( Index ); +} + +// Methoden von XEnumerationAccess +// Schon in XNameAccess: virtual Reference<XIdlClass> getElementType(void) const; +Reference<XEnumeration> ImplIntrospectionAdapter::createEnumeration(void) throw( RuntimeException ) +{ + return mxObjEnumerationAccess->createEnumeration(); +} + +// Methoden von XIdlArray +void ImplIntrospectionAdapter::realloc(Any& array, sal_Int32 length) + throw( IllegalArgumentException, RuntimeException ) +{ + mxObjIdlArray->realloc( array, length ); +} + +sal_Int32 ImplIntrospectionAdapter::getLen(const Any& array) + throw( IllegalArgumentException, RuntimeException ) +{ + return mxObjIdlArray->getLen( array ); +} + +Any ImplIntrospectionAdapter::get(const Any& array, sal_Int32 index) + throw( IllegalArgumentException, ArrayIndexOutOfBoundsException, RuntimeException ) +{ + return mxObjIdlArray->get( array, index ); +} + +void ImplIntrospectionAdapter::set(Any& array, sal_Int32 index, const Any& value) + throw( IllegalArgumentException, ArrayIndexOutOfBoundsException, RuntimeException ) +{ + mxObjIdlArray->set( array, index, value ); +} + + +//************************************************** +//*** Implementation von ImplIntrospectionAccess *** +//************************************************** + +// Methoden von XIntrospectionAccess +sal_Int32 ImplIntrospectionAccess::getSuppliedMethodConcepts(void) + throw( RuntimeException ) +{ + return MethodConcept::DANGEROUS | + PROPERTY | + LISTENER | + ENUMERATION | + NAMECONTAINER | + INDEXCONTAINER; +} + +sal_Int32 ImplIntrospectionAccess::getSuppliedPropertyConcepts(void) + throw( RuntimeException ) +{ + return PropertyConcept::DANGEROUS | + PROPERTYSET | + ATTRIBUTES | + METHODS; +} + +Property ImplIntrospectionAccess::getProperty(const OUString& Name, sal_Int32 PropertyConcepts) + throw( NoSuchElementException, RuntimeException ) +{ + Property aRet; + sal_Int32 i = mpStaticImpl->getPropertyIndex( Name ); + sal_Bool bFound = sal_False; + if( i != -1 ) + { + sal_Int32 nConcept = mpStaticImpl->getPropertyConcepts().getConstArray()[ i ]; + if( (PropertyConcepts & nConcept) != 0 ) + { + const Property* pProps = mpStaticImpl->getProperties().getConstArray(); + aRet = pProps[ i ]; + bFound = sal_True; + } + } + if( !bFound ) + throw NoSuchElementException() ; + return aRet; +} + +sal_Bool ImplIntrospectionAccess::hasProperty(const OUString& Name, sal_Int32 PropertyConcepts) + throw( RuntimeException ) +{ + sal_Int32 i = mpStaticImpl->getPropertyIndex( Name ); + sal_Bool bRet = sal_False; + if( i != -1 ) + { + sal_Int32 nConcept = mpStaticImpl->getPropertyConcepts().getConstArray()[ i ]; + if( (PropertyConcepts & nConcept) != 0 ) + bRet = sal_True; + } + return bRet; +} + +Sequence< Property > ImplIntrospectionAccess::getProperties(sal_Int32 PropertyConcepts) + throw( RuntimeException ) +{ + // Wenn alle unterstuetzten Konzepte gefordert werden, Sequence einfach durchreichen + sal_Int32 nAllSupportedMask = PROPERTYSET | + ATTRIBUTES | + METHODS; + if( ( PropertyConcepts & nAllSupportedMask ) == nAllSupportedMask ) + { + return mpStaticImpl->getProperties(); + } + + // Gleiche Sequence wie beim vorigen mal? + if( mnLastPropertyConcept == PropertyConcepts ) + { + return maLastPropertySeq; + } + + // Anzahl der zu liefernden Properties + sal_Int32 nCount = 0; + + // Es gibt zur Zeit keine DANGEROUS-Properties + // if( PropertyConcepts & DANGEROUS ) + // nCount += mpStaticImpl->mnDangerousPropCount; + if( PropertyConcepts & PROPERTYSET ) + nCount += mpStaticImpl->mnPropertySetPropCount; + if( PropertyConcepts & ATTRIBUTES ) + nCount += mpStaticImpl->mnAttributePropCount; + if( PropertyConcepts & METHODS ) + nCount += mpStaticImpl->mnMethodPropCount; + + // Sequence entsprechend der geforderten Anzahl reallocieren + ImplIntrospectionAccess* pThis = (ImplIntrospectionAccess*)this; // const umgehen + pThis->maLastPropertySeq.realloc( nCount ); + Property* pDestProps = pThis->maLastPropertySeq.getArray(); + + // Alle Properties durchgehen und entsprechend der Concepte uebernehmen + Sequence<Property> aPropSeq = mpStaticImpl->getProperties(); + const Property* pSourceProps = aPropSeq.getConstArray(); + const sal_Int32* pConcepts = mpStaticImpl->getPropertyConcepts().getConstArray(); + sal_Int32 nLen = aPropSeq.getLength(); + + sal_Int32 iDest = 0; + for( sal_Int32 i = 0 ; i < nLen ; i++ ) + { + sal_Int32 nConcept = pConcepts[ i ]; + if( nConcept & PropertyConcepts ) + pDestProps[ iDest++ ] = pSourceProps[ i ]; + } + + // PropertyConcept merken, dies entspricht maLastPropertySeq + pThis->mnLastPropertyConcept = PropertyConcepts; + + // Zusammengebastelte Sequence liefern + return maLastPropertySeq; +} + +Reference<XIdlMethod> ImplIntrospectionAccess::getMethod(const OUString& Name, sal_Int32 MethodConcepts) + throw( NoSuchMethodException, RuntimeException ) +{ + Reference<XIdlMethod> xRet; + sal_Int32 i = mpStaticImpl->getMethodIndex( Name ); + if( i != -1 ) + { + + sal_Int32 nConcept = mpStaticImpl->getMethodConcepts().getConstArray()[ i ]; + if( (MethodConcepts & nConcept) != 0 ) + { + const Reference<XIdlMethod>* pMethods = mpStaticImpl->getMethods().getConstArray(); + xRet = pMethods[i]; + } + } + if( !xRet.is() ) + throw NoSuchMethodException(); + return xRet; +} + +sal_Bool ImplIntrospectionAccess::hasMethod(const OUString& Name, sal_Int32 MethodConcepts) + throw( RuntimeException ) +{ + sal_Int32 i = mpStaticImpl->getMethodIndex( Name ); + sal_Bool bRet = sal_False; + if( i != -1 ) + { + sal_Int32 nConcept = mpStaticImpl->getMethodConcepts().getConstArray()[ i ]; + if( (MethodConcepts & nConcept) != 0 ) + bRet = sal_True; + } + return bRet; +} + +Sequence< Reference<XIdlMethod> > ImplIntrospectionAccess::getMethods(sal_Int32 MethodConcepts) + throw( RuntimeException ) +{ + ImplIntrospectionAccess* pThis = (ImplIntrospectionAccess*)this; // const umgehen + + // Wenn alle unterstuetzten Konzepte gefordert werden, Sequence einfach durchreichen + sal_Int32 nAllSupportedMask = MethodConcept::DANGEROUS | + PROPERTY | + LISTENER | + ENUMERATION | + NAMECONTAINER | + INDEXCONTAINER | + MethodConcept_NORMAL_IMPL; + if( ( MethodConcepts & nAllSupportedMask ) == nAllSupportedMask ) + { + return mpStaticImpl->getMethods(); + } + + // Gleiche Sequence wie beim vorigen mal? + if( mnLastMethodConcept == MethodConcepts ) + { + return maLastMethodSeq; + } + + // Methoden-Sequences besorgen + Sequence< Reference<XIdlMethod> > aMethodSeq = mpStaticImpl->getMethods(); + const Reference<XIdlMethod>* pSourceMethods = aMethodSeq.getConstArray(); + const sal_Int32* pConcepts = mpStaticImpl->getMethodConcepts().getConstArray(); + sal_Int32 nLen = aMethodSeq.getLength(); + + // Sequence entsprechend der geforderten Anzahl reallocieren + // Anders als bei den Properties kann die Anzahl nicht durch + // Zaehler in inspect() vorher ermittelt werden, da Methoden + // mehreren Konzepten angehoeren koennen + pThis->maLastMethodSeq.realloc( nLen ); + Reference<XIdlMethod>* pDestMethods = pThis->maLastMethodSeq.getArray(); + + // Alle Methods durchgehen und entsprechend der Concepte uebernehmen + sal_Int32 iDest = 0; + for( sal_Int32 i = 0 ; i < nLen ; i++ ) + { + sal_Int32 nConcept = pConcepts[ i ]; + if( nConcept & MethodConcepts ) + pDestMethods[ iDest++ ] = pSourceMethods[ i ]; + + #if OSL_DEBUG_LEVEL > 0 + static bool debug = false; + if ( debug ) + { + // Methode mit Concepts ausgeben + const Reference< XIdlMethod >& rxMethod = pSourceMethods[ i ]; + ::rtl::OString aNameStr = ::rtl::OUStringToOString( rxMethod->getName(), osl_getThreadTextEncoding() ); + ::rtl::OString ConceptStr; + if( nConcept & MethodConcept::DANGEROUS ) + ConceptStr += "DANGEROUS |"; + if( nConcept & MethodConcept::PROPERTY ) + ConceptStr += "PROPERTY |"; + if( nConcept & MethodConcept::LISTENER ) + ConceptStr += "LISTENER |"; + if( nConcept & MethodConcept::ENUMERATION ) + ConceptStr += "ENUMERATION |"; + if( nConcept & MethodConcept::NAMECONTAINER ) + ConceptStr += "NAMECONTAINER |"; + if( nConcept & MethodConcept::INDEXCONTAINER ) + ConceptStr += "INDEXCONTAINER |"; + OSL_TRACE( "Method %ld: %s, Concepts = %s", i, aNameStr.getStr(), ConceptStr.getStr() ); + } + #endif + } + + // Auf die richtige Laenge bringen + pThis->maLastMethodSeq.realloc( iDest ); + + // MethodConcept merken, dies entspricht maLastMethodSeq + pThis->mnLastMethodConcept = MethodConcepts; + + // Zusammengebastelte Sequence liefern + return maLastMethodSeq; +} + +Sequence< Type > ImplIntrospectionAccess::getSupportedListeners(void) + throw( RuntimeException ) +{ + return mpStaticImpl->getSupportedListeners(); +} + +Reference<XInterface> SAL_CALL ImplIntrospectionAccess::queryAdapter( const Type& rType ) + throw( IllegalTypeException, RuntimeException ) +{ + // Gibt es schon einen Adapter? + if( !mpAdapter ) + { + ((ImplIntrospectionAccess*)this)->mpAdapter = + new ImplIntrospectionAdapter( this, maInspectedObject, mpStaticImpl ); + + // Selbst eine Referenz halten + mpAdapter->acquire(); + } + + Reference<XInterface> xRet; + Any aIfaceAny( mpAdapter->queryInterface( rType ) ); + if( aIfaceAny.hasValue() ) + xRet = *(Reference<XInterface>*)aIfaceAny.getValue(); + + return xRet; +} + +// Methoden von XMaterialHolder +Any ImplIntrospectionAccess::getMaterial(void) throw(RuntimeException) +{ + return maInspectedObject; +} + +// Hilfs-Funktion zur LowerCase-Wandlung eines OUString +OUString toLower( OUString aUStr ) +{ + // Tabelle fuer XExactName pflegen + ::rtl::OUString aOWStr( aUStr.getStr() ); + ::rtl::OUString aOWLowerStr = aOWStr.toAsciiLowerCase(); + OUString aLowerUStr( aOWLowerStr.getStr() ); + return aLowerUStr; +} + +// Methoden von XExactName +OUString ImplIntrospectionAccess::getExactName( const OUString& rApproximateName ) throw( RuntimeException ) +{ + OUString aRetStr; + LowerToExactNameMap::iterator aIt = + mpStaticImpl->maLowerToExactNameMap.find( toLower( rApproximateName ) ); + if( !( aIt == mpStaticImpl->maLowerToExactNameMap.end() ) ) + aRetStr = (*aIt).second; + return aRetStr; +} + + +//----------------------------------------------------------------------------- + +#ifdef USE_INTROSPECTION_CACHE + +struct hashIntrospectionKey_Impl +{ + Sequence< Reference<XIdlClass> > aIdlClasses; + Reference<XPropertySetInfo> xPropInfo; + Reference<XIdlClass> xImplClass; + sal_Int32 nHitCount; + + void IncHitCount() const { ((hashIntrospectionKey_Impl*)this)->nHitCount++; } + hashIntrospectionKey_Impl() : nHitCount( 0 ) {} + hashIntrospectionKey_Impl( const Sequence< Reference<XIdlClass> > & rIdlClasses, + const Reference<XPropertySetInfo> & rxPropInfo, + const Reference<XIdlClass> & rxImplClass ); +}; + +hashIntrospectionKey_Impl::hashIntrospectionKey_Impl +( + const Sequence< Reference<XIdlClass> > & rIdlClasses, + const Reference<XPropertySetInfo> & rxPropInfo, + const Reference<XIdlClass> & rxImplClass +) + : aIdlClasses( rIdlClasses ) + , xPropInfo( rxPropInfo ) + , xImplClass( rxImplClass ) + , nHitCount( 0 ) +{} + + +struct hashIntrospectionAccessCache_Impl +{ + size_t operator()(const hashIntrospectionKey_Impl & rObj ) const + { + return (size_t)rObj.xImplClass.get() ^ (size_t)rObj.xPropInfo.get(); + } + + bool operator()( const hashIntrospectionKey_Impl & rObj1, + const hashIntrospectionKey_Impl & rObj2 ) const + { + if( rObj1.xPropInfo != rObj2.xPropInfo + || rObj1.xImplClass != rObj2.xImplClass ) + return sal_False; + + sal_Int32 nCount1 = rObj1.aIdlClasses.getLength(); + sal_Int32 nCount2 = rObj2.aIdlClasses.getLength(); + if( nCount1 != nCount2 ) + return sal_False; + + const Reference<XIdlClass>* pRefs1 = rObj1.aIdlClasses.getConstArray(); + const Reference<XIdlClass>* pRefs2 = rObj2.aIdlClasses.getConstArray(); + return memcmp( pRefs1, pRefs2, nCount1 * sizeof( Reference<XIdlClass> ) ) == 0; + } + +}; + +typedef boost::unordered_map +< + hashIntrospectionKey_Impl, + IntrospectionAccessStatic_Impl*, + hashIntrospectionAccessCache_Impl, + hashIntrospectionAccessCache_Impl +> +IntrospectionAccessCacheMap_Impl; + +class IntrospectionAccessCacheMap : public IntrospectionAccessCacheMap_Impl +{ +public: + ~IntrospectionAccessCacheMap() + { + IntrospectionAccessCacheMap::iterator iter = begin(); + IntrospectionAccessCacheMap::iterator stop = this->end(); + while( iter != stop ) + { + + (*iter).second->release(); + (*iter).second = NULL; + ++iter; + } + } +}; + + +// For XTypeProvider +struct hashTypeProviderKey_Impl +{ + Reference<XPropertySetInfo> xPropInfo; + Sequence< sal_Int8 > maImpIdSeq; + sal_Int32 nHitCount; + + void IncHitCount() const { ((hashTypeProviderKey_Impl*)this)->nHitCount++; } + hashTypeProviderKey_Impl() : nHitCount( 0 ) {} + hashTypeProviderKey_Impl( const Reference<XPropertySetInfo> & rxPropInfo, const Sequence< sal_Int8 > & aImpIdSeq_ ); +}; + +hashTypeProviderKey_Impl::hashTypeProviderKey_Impl +( + const Reference<XPropertySetInfo> & rxPropInfo, + const Sequence< sal_Int8 > & aImpIdSeq_ +) + : xPropInfo( rxPropInfo ) + , maImpIdSeq( aImpIdSeq_ ) + , nHitCount( 0 ) +{} + + +struct TypeProviderAccessCache_Impl +{ + size_t operator()(const hashTypeProviderKey_Impl & rObj ) const; + + bool operator()( const hashTypeProviderKey_Impl & rObj1, + const hashTypeProviderKey_Impl & rObj2 ) const + { + if( rObj1.xPropInfo != rObj2.xPropInfo ) + return sal_False; + + bool bEqual = false; + sal_Int32 nLen1 = rObj1.maImpIdSeq.getLength(); + sal_Int32 nLen2 = rObj2.maImpIdSeq.getLength(); + if( nLen1 == nLen2 && nLen1 > 0 ) + { + const sal_Int8* pId1 = rObj1.maImpIdSeq.getConstArray(); + const sal_Int8* pId2 = rObj2.maImpIdSeq.getConstArray(); + bEqual = (memcmp( pId1, pId2, nLen1 * sizeof( sal_Int8 ) ) == 0 ); + } + return bEqual; + } +}; + +size_t TypeProviderAccessCache_Impl::operator()(const hashTypeProviderKey_Impl & rObj ) const +{ + const sal_Int32* pBytesAsInt32Array = (const sal_Int32*)rObj.maImpIdSeq.getConstArray(); + sal_Int32 nLen = rObj.maImpIdSeq.getLength(); + sal_Int32 nCount32 = nLen / 4; + sal_Int32 nMod32 = nLen % 4; + + // XOR with full 32 bit values + sal_Int32 nId32 = 0; + sal_Int32 i; + for( i = 0 ; i < nCount32 ; i++ ) + nId32 ^= *(pBytesAsInt32Array++); + + // XOR with remaining byte values + if( nMod32 ) + { + const sal_Int8* pBytes = (const sal_Int8*)pBytesAsInt32Array; + sal_Int8* pInt8_Id32 = (sal_Int8*)&nId32; + for( i = 0 ; i < nMod32 ; i++ ) + *(pInt8_Id32++) ^= *(pBytes++); + } + + return (size_t)nId32; +} + + +typedef boost::unordered_map +< + hashTypeProviderKey_Impl, + IntrospectionAccessStatic_Impl*, + TypeProviderAccessCache_Impl, + TypeProviderAccessCache_Impl +> +TypeProviderAccessCacheMap_Impl; + +class TypeProviderAccessCacheMap : public TypeProviderAccessCacheMap_Impl +{ +public: + ~TypeProviderAccessCacheMap() + { + TypeProviderAccessCacheMap::iterator iter = begin(); + TypeProviderAccessCacheMap::iterator stop = this->end(); + while( iter != stop ) + { + (*iter).second->release(); + (*iter).second = NULL; + ++iter; + } + } +}; + +#endif + + +//************************* +//*** ImplIntrospection *** +//************************* + +struct OIntrospectionMutex +{ + Mutex m_mutex; +}; + +class ImplIntrospection : public XIntrospection + , public XServiceInfo + , public OIntrospectionMutex + , public OComponentHelper +{ + friend class ImplMergeIntrospection; + friend class ImplMVCIntrospection; + + // Implementation der Introspection. + // ACHTUNG: RefCounting von Hand !!! + IntrospectionAccessStatic_Impl* implInspect(const Any& aToInspectObj); + + // Save XMultiServiceFactory from createComponent + Reference<XMultiServiceFactory> m_xSMgr; + + // CoreReflection halten + Reference< XIdlReflection > mxCoreReflection; + + // Klassen, deren Methoden eine spezielle Rolle spielen + Reference<XIdlClass> mxElementAccessClass; + Reference<XIdlClass> mxNameContainerClass; + Reference<XIdlClass> mxNameAccessClass; + Reference<XIdlClass> mxIndexContainerClass; + Reference<XIdlClass> mxIndexAccessClass; + Reference<XIdlClass> mxEnumerationAccessClass; + Reference<XIdlClass> mxInterfaceClass; + Reference<XIdlClass> mxAggregationClass; + sal_Bool mbDisposed; + +#ifdef USE_INTROSPECTION_CACHE + sal_uInt16 mnCacheEntryCount; + sal_uInt16 mnTPCacheEntryCount; + IntrospectionAccessCacheMap* mpCache; + TypeProviderAccessCacheMap* mpTypeProviderCache; +#endif + +public: + ImplIntrospection( const Reference<XMultiServiceFactory> & rXSMgr ); + + // Methoden von XInterface + virtual Any SAL_CALL queryInterface( const Type& rType ) throw( RuntimeException ); + virtual void SAL_CALL acquire() throw() { OComponentHelper::acquire(); } + virtual void SAL_CALL release() throw() { OComponentHelper::release(); } + + // XTypeProvider + Sequence< Type > SAL_CALL getTypes( ) throw( RuntimeException ); + Sequence<sal_Int8> SAL_CALL getImplementationId( ) throw( RuntimeException ); + + // XServiceInfo + OUString SAL_CALL getImplementationName() throw(); + sal_Bool SAL_CALL supportsService(const OUString& ServiceName) throw(); + Sequence< OUString > SAL_CALL getSupportedServiceNames(void) throw(); + static OUString SAL_CALL getImplementationName_Static( ); + static Sequence< OUString > SAL_CALL getSupportedServiceNames_Static(void) throw(); + + // Methoden von XIntrospection + virtual Reference<XIntrospectionAccess> SAL_CALL inspect(const Any& aToInspectObj) + throw( RuntimeException ); + +protected: + // some XComponent part from OComponentHelper + virtual void SAL_CALL dispose() throw(::com::sun::star::uno::RuntimeException); +}; + +enum MethodType +{ + STANDARD_METHOD, // normale Methode, kein Bezug zu Properties oder Listenern + GETSET_METHOD, // gehoert zu einer get/set-Property + ADD_LISTENER_METHOD, // add-Methode einer Listener-Schnittstelle + REMOVE_LISTENER_METHOD, // remove-Methode einer Listener-Schnittstelle + INVALID_METHOD // Methode, deren Klasse nicht beruecksichtigt wird, z.B. XPropertySet +}; + +// Ctor +ImplIntrospection::ImplIntrospection( const Reference<XMultiServiceFactory> & rXSMgr ) + : OComponentHelper( m_mutex ) + , m_xSMgr( rXSMgr ) +{ +#ifdef USE_INTROSPECTION_CACHE + mnCacheEntryCount = 0; + mnTPCacheEntryCount = 0; + mpCache = NULL; + mpTypeProviderCache = NULL; +#endif + + // Spezielle Klassen holen +// Reference< XInterface > xServiceIface = m_xSMgr->createInstance( OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.reflection.CoreReflection")) ); +// if( xServiceIface.is() ) +// mxCoreReflection = Reference< XIdlReflection >::query( xServiceIface ); + Reference< XPropertySet > xProps( rXSMgr, UNO_QUERY ); + OSL_ASSERT( xProps.is() ); + if (xProps.is()) + { + Reference< XComponentContext > xContext; + xProps->getPropertyValue( + OUString( RTL_CONSTASCII_USTRINGPARAM("DefaultContext") ) ) >>= xContext; + OSL_ASSERT( xContext.is() ); + if (xContext.is()) + { + xContext->getValueByName( + OUString( RTL_CONSTASCII_USTRINGPARAM("/singletons/com.sun.star.reflection.theCoreReflection") ) ) >>= mxCoreReflection; + OSL_ENSURE( mxCoreReflection.is(), "### CoreReflection singleton not accessible!?" ); + } + } + if (! mxCoreReflection.is()) + { + throw DeploymentException( + OUString( RTL_CONSTASCII_USTRINGPARAM("/singletons/com.sun.star.reflection.theCoreReflection singleton not accessible") ), + Reference< XInterface >() ); + } + + mxElementAccessClass = mxCoreReflection->forName( OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.container.XElementAccess")) ); + mxNameContainerClass = mxCoreReflection->forName( OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.container.XNameContainer")) ); + mxNameAccessClass = mxCoreReflection->forName( OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.container.XNameAccess")) ); + mxIndexContainerClass = mxCoreReflection->forName( OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.container.XIndexContainer")) ); + mxIndexAccessClass = mxCoreReflection->forName( OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.container.XIndexAccess")) ); + mxEnumerationAccessClass = mxCoreReflection->forName( OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.container.XEnumerationAccess")) ); + mxInterfaceClass = mxCoreReflection->forName( OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.uno.XInterface")) ); + mxAggregationClass = mxCoreReflection->forName( OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.uno.XAggregation")) ); + mbDisposed = sal_False; +} + +// XComponent +void ImplIntrospection::dispose() throw(::com::sun::star::uno::RuntimeException) +{ + OComponentHelper::dispose(); + +#ifdef USE_INTROSPECTION_CACHE + // Cache loeschen + delete mpCache; + mpCache = NULL; + delete mpTypeProviderCache; + mpTypeProviderCache = NULL; +#endif + + mxElementAccessClass = NULL; + mxNameContainerClass = NULL; + mxNameAccessClass = NULL; + mxIndexContainerClass = NULL; + mxIndexAccessClass = NULL; + mxEnumerationAccessClass = NULL; + mxInterfaceClass = NULL; + mxAggregationClass = NULL; + mbDisposed = sal_True; +} + + +//----------------------------------------------------------------------------- + +// XInterface +Any ImplIntrospection::queryInterface( const Type & rType ) + throw(::com::sun::star::uno::RuntimeException) +{ + Any aRet( ::cppu::queryInterface( + rType, + static_cast< XIntrospection * >( this ), + static_cast< XServiceInfo * >( this ) ) ); + + return (aRet.hasValue() ? aRet : OComponentHelper::queryInterface( rType )); +} + +// XTypeProvider +Sequence< Type > ImplIntrospection::getTypes() + throw( RuntimeException ) +{ + static OTypeCollection * s_pTypes = 0; + if (! s_pTypes) + { + MutexGuard aGuard( Mutex::getGlobalMutex() ); + if (! s_pTypes) + { + static OTypeCollection s_aTypes( + ::getCppuType( (const Reference< XIntrospection > *)0 ), + ::getCppuType( (const Reference< XServiceInfo > *)0 ), + OComponentHelper::getTypes() ); + s_pTypes = &s_aTypes; + } + } + return s_pTypes->getTypes(); +} + +Sequence< sal_Int8 > ImplIntrospection::getImplementationId() + throw( RuntimeException ) +{ + static OImplementationId * s_pId = 0; + if (! s_pId) + { + MutexGuard aGuard( Mutex::getGlobalMutex() ); + if (! s_pId) + { + static OImplementationId s_aId; + s_pId = &s_aId; + } + } + return s_pId->getImplementationId(); +} + + +// XServiceInfo +OUString ImplIntrospection::getImplementationName() throw() +{ + return getImplementationName_Static(); +} + +// XServiceInfo +sal_Bool ImplIntrospection::supportsService(const OUString& ServiceName) throw() +{ + Sequence< OUString > aSNL = getSupportedServiceNames(); + const OUString * pArray = aSNL.getConstArray(); + for( sal_Int32 i = 0; i < aSNL.getLength(); i++ ) + if( pArray[i] == ServiceName ) + return sal_True; + return sal_False; +} + +// XServiceInfo +Sequence< OUString > ImplIntrospection::getSupportedServiceNames(void) throw() +{ + return getSupportedServiceNames_Static(); +} + +//************************************************************************* +// Helper XServiceInfo +OUString ImplIntrospection::getImplementationName_Static( ) +{ + return OUString(RTL_CONSTASCII_USTRINGPARAM(IMPLEMENTATION_NAME)); +} + +// ORegistryServiceManager_Static +Sequence< OUString > ImplIntrospection::getSupportedServiceNames_Static(void) throw() +{ + Sequence< OUString > aSNS( 1 ); + aSNS.getArray()[0] = OUString(RTL_CONSTASCII_USTRINGPARAM(SERVICE_NAME)); + return aSNS; +} + +//************************************************************************* + +// Methoden von XIntrospection +Reference<XIntrospectionAccess> ImplIntrospection::inspect(const Any& aToInspectObj) + throw( RuntimeException ) +{ + Reference<XIntrospectionAccess> xAccess; + + if ( aToInspectObj.getValueType().getTypeClass() == TypeClass_TYPE ) + { + Type aType; + aToInspectObj >>= aType; + + Reference< XIdlClass > xIdlClass = mxCoreReflection->forName(((Type*)(aToInspectObj.getValue()))->getTypeName()); + + if ( xIdlClass.is() ) + { + Any aRealInspectObj; + aRealInspectObj <<= xIdlClass; + + IntrospectionAccessStatic_Impl* pStaticImpl = implInspect( aRealInspectObj ); + if( pStaticImpl ) + xAccess = new ImplIntrospectionAccess( aRealInspectObj, pStaticImpl ); + } + } + else + { + IntrospectionAccessStatic_Impl* pStaticImpl = implInspect( aToInspectObj ); + if( pStaticImpl ) + xAccess = new ImplIntrospectionAccess( aToInspectObj, pStaticImpl ); + } + + return xAccess; +} + +//----------------------------------------------------------------------------- + +// Hashtable fuer Pruefung auf mehrfache Beruecksichtigung von Interfaces +struct hashInterface_Impl +{ + size_t operator()(const void* p) const + { + return (size_t)p; + } +}; + +struct eqInterface_Impl +{ + bool operator()(const void* p1, const void* p2) const + { + return ( p1 == p2 ); + } +}; + +typedef boost::unordered_map +< + void*, + void*, + hashInterface_Impl, + eqInterface_Impl +> +CheckedInterfacesMap; + + + +// TODO: Spaeter auslagern +Reference<XIdlClass> TypeToIdlClass( const Type& rType, const Reference< XMultiServiceFactory > & xMgr ) +{ + static Reference< XIdlReflection > xRefl; + + // void als Default-Klasse eintragen + Reference<XIdlClass> xRetClass; + typelib_TypeDescription * pTD = 0; + rType.getDescription( &pTD ); + if( pTD ) + { + OUString sOWName( pTD->pTypeName ); + if( !xRefl.is() ) + { + xRefl = Reference< XIdlReflection >( xMgr->createInstance( OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.reflection.CoreReflection")) ), UNO_QUERY ); + OSL_ENSURE( xRefl.is(), "### no corereflection!" ); + } + xRetClass = xRefl->forName( sOWName ); + } + return xRetClass; +} + +// Implementation der Introspection. +IntrospectionAccessStatic_Impl* ImplIntrospection::implInspect(const Any& aToInspectObj) +{ + MutexGuard aGuard( m_mutex ); + + // Wenn die Introspection schon disposed ist, wird nur ein leeres Ergebnis geliefert + if( mbDisposed ) + return NULL; + + // Objekt untersuchen + TypeClass eType = aToInspectObj.getValueType().getTypeClass(); + if( eType != TypeClass_INTERFACE && eType != TypeClass_STRUCT && eType != TypeClass_EXCEPTION ) + return NULL; + + Reference<XInterface> x; + if( eType == TypeClass_INTERFACE ) + { + // Interface aus dem Any besorgen + x = *(Reference<XInterface>*)aToInspectObj.getValue(); + if( !x.is() ) + return NULL; + } + +#ifdef USE_INTROSPECTION_CACHE + // Haben wir schon eine Cache-Instanz + if( !mpCache ) + mpCache = new IntrospectionAccessCacheMap; + if( !mpTypeProviderCache ) + mpTypeProviderCache = new TypeProviderAccessCacheMap; + IntrospectionAccessCacheMap& aCache = *mpCache; + TypeProviderAccessCacheMap& aTPCache = *mpTypeProviderCache; + + // Pointer auf ggf. noetige neue IntrospectionAccess-Instanz + IntrospectionAccessStatic_Impl* pAccess = NULL; +#else + // Pointer auf ggf. noetige neue IntrospectionAccess-Instanz + IntrospectionAccessStatic_Impl* pAccess = new IntrospectionAccessStatic_Impl( mxCoreReflection ); +#endif + + // Pruefen: Ist schon ein passendes Access-Objekt gecached? + Sequence< Reference<XIdlClass> > SupportedClassSeq; + Sequence< Type > SupportedTypesSeq; + Reference<XIdlClassProvider> xClassProvider; + Reference<XTypeProvider> xTypeProvider; + Reference<XIdlClass> xImplClass; + Reference<XPropertySetInfo> xPropSetInfo; + Reference<XPropertySet> xPropSet; + + // Bei Interfaces XTypeProvider / XIdlClassProvider- und PropertySet-Interface anfordern + if( eType == TypeClass_INTERFACE ) + { + // XIdlClassProvider + xTypeProvider = Reference<XTypeProvider>::query( x ); + if( xTypeProvider.is() ) + { + SupportedTypesSeq = xTypeProvider->getTypes(); + sal_Int32 nTypeCount = SupportedTypesSeq.getLength(); + if( nTypeCount ) + { + SupportedClassSeq.realloc( nTypeCount ); + Reference<XIdlClass>* pClasses = SupportedClassSeq.getArray(); + + const Type* pTypes = SupportedTypesSeq.getConstArray(); + for( sal_Int32 i = 0 ; i < nTypeCount ; i++ ) + { + pClasses[ i ] = TypeToIdlClass( pTypes[ i ], m_xSMgr ); + } + // TODO: Caching! + } + } + else + { + // XIdlClassProvider + xClassProvider = Reference<XIdlClassProvider>::query( x ); + if( xClassProvider.is() ) + { + SupportedClassSeq = xClassProvider->getIdlClasses(); + if( SupportedClassSeq.getLength() ) + xImplClass = SupportedClassSeq.getConstArray()[0]; + } + } + // #70197, fuer InvocationAdapter: Interface-Typ im Any auch ohne + // ClassProvider unterstuetzen + if( !xClassProvider.is() && !xTypeProvider.is() ) + { + xImplClass = TypeToIdlClass( aToInspectObj.getValueType(), m_xSMgr ); + SupportedClassSeq.realloc( 1 ); + SupportedClassSeq.getArray()[ 0 ] = xImplClass; + } + + xPropSet = Reference<XPropertySet>::query( x ); + // Jetzt versuchen, das PropertySetInfo zu bekommen + if( xPropSet.is() ) + xPropSetInfo = xPropSet->getPropertySetInfo(); + } + else + { + xImplClass = TypeToIdlClass( aToInspectObj.getValueType(), m_xSMgr ); + } + +#ifdef USE_INTROSPECTION_CACHE + if( xTypeProvider.is() ) + { + Sequence< sal_Int8 > aImpIdSeq = xTypeProvider->getImplementationId(); + sal_Int32 nIdLen = aImpIdSeq.getLength(); + + if( nIdLen ) + { + // cache only, if the descriptor class is set + hashTypeProviderKey_Impl aKeySeq( xPropSetInfo, aImpIdSeq ); + + TypeProviderAccessCacheMap::iterator aIt = aTPCache.find( aKeySeq ); + if( aIt == aTPCache.end() ) + { + // not found + // Neue Instanz anlegen und unter dem gegebenen Key einfuegen + pAccess = new IntrospectionAccessStatic_Impl( mxCoreReflection ); + + // RefCount von Hand erhoehen, muss beim Entfernen + // aus der Hashtable wieder released werden + pAccess->acquire(); + + // Groesse begrenzen, alten Eintrag wieder rausschmeissen + if( mnTPCacheEntryCount > INTROSPECTION_CACHE_MAX_SIZE ) + { + // Access mit dem kleinsten HitCount suchen + TypeProviderAccessCacheMap::iterator iter = aTPCache.begin(); + TypeProviderAccessCacheMap::iterator end = aTPCache.end(); + TypeProviderAccessCacheMap::iterator toDelete = iter; + while( iter != end ) + { + if( (*iter).first.nHitCount < (*toDelete).first.nHitCount ) + toDelete = iter; + ++iter; + } + + // Gefundenen Eintrag entfernen + if( (*toDelete).second ) + (*toDelete).second->release(); + (*toDelete).second = NULL; + aTPCache.erase( toDelete ); + } + else + mnTPCacheEntryCount++; + + // Neuer Eintrage rein in die Table + aKeySeq.nHitCount = 1; + aTPCache[ aKeySeq ] = pAccess; + + } + else + { + // Hit-Count erhoehen + (*aIt).first.IncHitCount(); + return (*aIt).second; + } + } + } + else if( xImplClass.is() ) + { + // cache only, if the descriptor class is set + hashIntrospectionKey_Impl aKeySeq( SupportedClassSeq, xPropSetInfo, xImplClass ); + + IntrospectionAccessCacheMap::iterator aIt = aCache.find( aKeySeq ); + if( aIt == aCache.end() ) + { + // not found + // Neue Instanz anlegen und unter dem gegebenen Key einfuegen + pAccess = new IntrospectionAccessStatic_Impl( mxCoreReflection ); + + // RefCount von Hand erhoehen, muss beim Entfernen + // aus der Hashtable wieder released werden + pAccess->acquire(); + + // Groesse begrenzen, alten Eintrag wieder rausschmeissen + if( mnCacheEntryCount > INTROSPECTION_CACHE_MAX_SIZE ) + { + // Access mit dem kleinsten HitCount suchen + IntrospectionAccessCacheMap::iterator iter = aCache.begin(); + IntrospectionAccessCacheMap::iterator end = aCache.end(); + IntrospectionAccessCacheMap::iterator toDelete = iter; + while( iter != end ) + { + if( (*iter).first.nHitCount < (*toDelete).first.nHitCount ) + toDelete = iter; + ++iter; + } + + // Gefundenen Eintrag entfernen + if( (*toDelete).second ) + (*toDelete).second->release(); + (*toDelete).second = NULL; + aCache.erase( toDelete ); + } + else + mnCacheEntryCount++; + + // Neuer Eintrage rein in die Table + aKeySeq.nHitCount = 1; + aCache[ aKeySeq ] = pAccess; + + } + else + { + // Hit-Count erhoehen + (*aIt).first.IncHitCount(); + return (*aIt).second; + } + } +#endif + + // Kein Access gecached -> neu anlegen + Property* pAllPropArray; + Reference<XInterface>* pInterfaces1; + Reference<XInterface>* pInterfaces2; + sal_Int16* pMapTypeArray; + sal_Int32* pPropertyConceptArray; + sal_Int32 i; + + if( !pAccess ) + pAccess = new IntrospectionAccessStatic_Impl( mxCoreReflection ); + + // Referenzen auf wichtige Daten von pAccess + sal_Int32& rPropCount = pAccess->mnPropCount; + IntrospectionNameMap& rPropNameMap = pAccess->maPropertyNameMap; + IntrospectionNameMap& rMethodNameMap = pAccess->maMethodNameMap; + LowerToExactNameMap& rLowerToExactNameMap = pAccess->maLowerToExactNameMap; + + // Schon mal Pointer auf das eigene Property-Feld holen + pAllPropArray = pAccess->maAllPropertySeq.getArray(); + pInterfaces1 = pAccess->aInterfaceSeq1.getArray(); + pInterfaces2 = pAccess->aInterfaceSeq2.getArray(); + pMapTypeArray = pAccess->maMapTypeSeq.getArray(); + pPropertyConceptArray = pAccess->maPropertyConceptSeq.getArray(); + + //************************* + //*** Analyse vornehmen *** + //************************* + if( eType == TypeClass_INTERFACE ) + { + // Zunaechst nach speziellen Interfaces suchen, die fuer + // die Introspection von besonderer Bedeutung sind. + + // XPropertySet vorhanden? + if( xPropSet.is() && xPropSetInfo.is() ) + { + // Gibt es auch ein FastPropertySet? + Reference<XFastPropertySet> xDummy = Reference<XFastPropertySet>::query( x ); + sal_Bool bFast = pAccess->mbFastPropSet = xDummy.is(); + + Sequence<Property> aPropSeq = xPropSetInfo->getProperties(); + const Property* pProps = aPropSeq.getConstArray(); + sal_Int32 nLen = aPropSeq.getLength(); + + // Bei FastPropertySet muessen wir uns die Original-Handles merken + if( bFast ) + pAccess->mpOrgPropertyHandleArray = new sal_Int32[ nLen ]; + + for( i = 0 ; i < nLen ; i++ ) + { + // Property in eigene Liste uebernehmen + pAccess->checkPropertyArraysSize + ( pAllPropArray, pMapTypeArray, pPropertyConceptArray, rPropCount ); + Property& rProp = pAllPropArray[ rPropCount ]; + rProp = pProps[ i ]; + + if( bFast ) + pAccess->mpOrgPropertyHandleArray[ i ] = rProp.Handle; + + // PropCount als Handle fuer das eigene FastPropertySet eintragen + rProp.Handle = rPropCount; + + // Art der Property merken + pMapTypeArray[ rPropCount ] = MAP_PROPERTY_SET; + pPropertyConceptArray[ rPropCount ] = PROPERTYSET; + pAccess->mnPropertySetPropCount++; + + // Namen in Hashtable eintragen, wenn nicht schon bekannt + OUString aPropName = rProp.Name; + + // Haben wir den Namen schon? + IntrospectionNameMap::iterator aIt = rPropNameMap.find( aPropName ); + if( aIt == rPropNameMap.end() ) + { + // Neuer Eintrag in die Hashtable + rPropNameMap[ aPropName ] = rPropCount; + + // Tabelle fuer XExactName pflegen + rLowerToExactNameMap[ toLower( aPropName ) ] = aPropName; + } + else + { + OSL_FAIL( OString( "Introspection: Property \"" ) + + OUStringToOString( aPropName, RTL_TEXTENCODING_ASCII_US ) + + OString( "\" found more than once in PropertySet" ) ); + } + + // Count pflegen + rPropCount++; + } + } + + + // Jetzt alle weiteren implementierten Interfaces durchgehen + // Diese muessen durch das XIdlClassProvider-Interface geliefert werden. + // #70197, fuer InvocationAdapter: Interface-Typ im Any auch ohne + // ClassProvider unterstuetzen + //if( xClassProvider.is() ) + { + // Indizes in die Export-Tabellen + sal_Int32 iAllExportedMethod = 0; + sal_Int32 iAllSupportedListener = 0; + + // Hashtable fuer Pruefung auf mehrfache Beruecksichtigung von Interfaces + CheckedInterfacesMap aCheckedInterfacesMap; + + // Flag, ob XInterface-Methoden erfasst werden sollen + // (das darf nur einmal erfolgen, initial zulassen) + sal_Bool bXInterfaceIsInvalid = sal_False; + + // Flag, ob die XInterface-Methoden schon erfasst wurden. Wenn sal_True, + // wird bXInterfaceIsInvalid am Ende der Iface-Schleife aktiviert und + // XInterface-Methoden werden danach abgeklemmt. + sal_Bool bFoundXInterface = sal_False; + + // Schleife ueber alle vom ClassProvider angegebenen Klassen + sal_Int32 nClassCount = SupportedClassSeq.getLength(); + for( sal_Int32 nIdx = 0 ; nIdx < nClassCount; nIdx++ ) + { + Reference<XIdlClass> xImplClass2 = SupportedClassSeq.getConstArray()[nIdx]; + while( xImplClass2.is() ) + { + // Interfaces der Implementation holen + Sequence< Reference<XIdlClass> > aClassSeq = xImplClass2->getInterfaces(); + sal_Int32 nIfaceCount = aClassSeq.getLength(); + + aClassSeq.realloc( nIfaceCount + 1 ); + aClassSeq.getArray()[ nIfaceCount ] = xImplClass2; + nIfaceCount++; + + const Reference<XIdlClass>* pParamArray = aClassSeq.getConstArray(); + + for( sal_Int32 j = 0 ; j < nIfaceCount ; j++ ) + { + const Reference<XIdlClass>& rxIfaceClass = pParamArray[j]; + + // Pruefen, ob das Interface schon beruecksichtigt wurde. + XInterface* pIface = SAL_STATIC_CAST( XInterface*, rxIfaceClass.get() ); + if( aCheckedInterfacesMap.count( pIface ) > 0 ) + { + // Kennen wir schon + continue; + } + else + { + // Sonst eintragen + aCheckedInterfacesMap[ pIface ] = pIface; + } + + //******************************************************************** + + // 2. Fields als Properties registrieren + + // Felder holen + Sequence< Reference<XIdlField> > fields = rxIfaceClass->getFields(); + const Reference<XIdlField>* pFields = fields.getConstArray(); + sal_Int32 nLen = fields.getLength(); + + for( i = 0 ; i < nLen ; i++ ) + { + Reference<XIdlField> xField = pFields[i]; + Reference<XIdlClass> xPropType = xField->getType(); + + // Ist die PropertySequence gross genug? + pAccess->checkPropertyArraysSize + ( pAllPropArray, pMapTypeArray, pPropertyConceptArray, rPropCount ); + + // In eigenes Property-Array eintragen + Property& rProp = pAllPropArray[ rPropCount ]; + OUString aFieldName = xField->getName(); + rProp.Name = aFieldName; + rProp.Handle = rPropCount; + Type aFieldType( xPropType->getTypeClass(), xPropType->getName() ); + rProp.Type = aFieldType; + FieldAccessMode eAccessMode = xField->getAccessMode(); + rProp.Attributes = (eAccessMode == FieldAccessMode_READONLY || + eAccessMode == FieldAccessMode_CONST) + ? READONLY : 0; + + // Namen in Hashtable eintragen + OUString aPropName = rProp.Name; + + // Haben wir den Namen schon? + IntrospectionNameMap::iterator aIt = rPropNameMap.find( aPropName ); + if( !( aIt == rPropNameMap.end() ) ) + { + /* TODO + OSL_TRACE( + String( "Introspection: Property \"" ) + + OOUStringToString( aPropName, CHARSET_SYSTEM ) + + String( "\" found more than once" ) ); + */ + continue; + } + + // Neuer Eintrag in die Hashtable + rPropNameMap[ aPropName ] = rPropCount; + + // Tabelle fuer XExactName pflegen + rLowerToExactNameMap[ toLower( aPropName ) ] = aPropName; + + // Field merken + pAccess->checkInterfaceArraySize( pAccess->aInterfaceSeq1, + pInterfaces1, rPropCount ); + pInterfaces1[ rPropCount ] = xField; + + // Art der Property merken + pMapTypeArray[ rPropCount ] = MAP_FIELD; + pPropertyConceptArray[ rPropCount ] = ATTRIBUTES; + pAccess->mnAttributePropCount++; + + // Count pflegen + rPropCount++; + } + + //******************************************************************** + + // 3. Methoden + + // Zaehler fuer die gefundenen Listener + sal_Int32 nListenerCount = 0; + + // Alle Methoden holen und merken + Sequence< Reference<XIdlMethod> > methods = rxIfaceClass->getMethods(); + const Reference<XIdlMethod>* pSourceMethods = methods.getConstArray(); + sal_Int32 nSourceMethodCount = methods.getLength(); + + // 3. a) get/set- und Listener-Methoden suchen + + // Feld fuer Infos ueber die Methoden anlegen, damit spaeter leicht die Methoden + // gefunden werden koennen, die nicht im Zusammenhang mit Properties oder Listenern + // stehen. NEU: auch MethodConceptArray initialisieren + MethodType* pMethodTypes = new MethodType[ nSourceMethodCount ]; + sal_Int32* pLocalMethodConcepts = new sal_Int32[ nSourceMethodCount ]; + for( i = 0 ; i < nSourceMethodCount ; i++ ) + { + pMethodTypes[ i ] = STANDARD_METHOD; + pLocalMethodConcepts[ i ] = 0; + } + + OUString aMethName; + OUString aPropName; + OUString aStartStr; + for( i = 0 ; i < nSourceMethodCount ; i++ ) + { + // Methode ansprechen + const Reference<XIdlMethod>& rxMethod_i = pSourceMethods[i]; + sal_Int32& rMethodConcept_i = pLocalMethodConcepts[ i ]; + + // Namen besorgen + aMethName = rxMethod_i->getName(); + + // Methoden katalogisieren + // Alle (?) Methoden von XInterface filtern, damit z.B. nicht + // vom Scripting aus aquire oder release gerufen werden kann + if( rxMethod_i->getDeclaringClass()->equals( mxInterfaceClass ) ) + { + // XInterface-Methoden sind hiermit einmal beruecksichtigt + bFoundXInterface = sal_True; + + if( bXInterfaceIsInvalid ) + { + pMethodTypes[ i ] = INVALID_METHOD; + continue; + } + else + { + if( aMethName != OUString( RTL_CONSTASCII_USTRINGPARAM("queryInterface")) ) + { + rMethodConcept_i |= MethodConcept::DANGEROUS; + continue; + } + } + } + else if( rxMethod_i->getDeclaringClass()->equals( mxAggregationClass ) ) + { + if( aMethName == OUString( RTL_CONSTASCII_USTRINGPARAM("setDelegator")) ) + { + rMethodConcept_i |= MethodConcept::DANGEROUS; + continue; + } + } + else if( rxMethod_i->getDeclaringClass()->equals( mxElementAccessClass ) ) + { + rMethodConcept_i |= ( NAMECONTAINER | + INDEXCONTAINER | + ENUMERATION ); + } + else if( rxMethod_i->getDeclaringClass()->equals( mxNameContainerClass ) || + rxMethod_i->getDeclaringClass()->equals( mxNameAccessClass ) ) + { + rMethodConcept_i |= NAMECONTAINER; + } + else if( rxMethod_i->getDeclaringClass()->equals( mxIndexContainerClass ) || + rxMethod_i->getDeclaringClass()->equals( mxIndexAccessClass ) ) + { + rMethodConcept_i |= INDEXCONTAINER; + } + else if( rxMethod_i->getDeclaringClass()->equals( mxEnumerationAccessClass ) ) + { + rMethodConcept_i |= ENUMERATION; + } + + // Wenn der Name zu kurz ist, wird's sowieso nichts + if( aMethName.getLength() <= 3 ) + continue; + + // Ist es eine get-Methode? + aStartStr = aMethName.copy( 0, 3 ); + if( aStartStr == OUString( RTL_CONSTASCII_USTRINGPARAM("get")) ) + { + // Namen der potentiellen Property + aPropName = aMethName.copy( 3 ); + + // get-Methode darf keinen Parameter haben + Sequence< Reference<XIdlClass> > getParams = rxMethod_i->getParameterTypes(); + if( getParams.getLength() > 0 ) + { + continue; + } + + // Haben wir den Namen schon? + IntrospectionNameMap::iterator aIt = rPropNameMap.find( aPropName ); + if( !( aIt == rPropNameMap.end() ) ) + { + /* TODO + OSL_TRACE( + String( "Introspection: Property \"" ) + + OOUStringToString( aPropName, CHARSET_SYSTEM ) + + String( "\" found more than once" ) ); + */ + continue; + } + + // Eine readonly-Property ist es jetzt mindestens schon + rMethodConcept_i |= PROPERTY; + + pMethodTypes[i] = GETSET_METHOD; + Reference<XIdlClass> xGetRetType = rxMethod_i->getReturnType(); + + // Ist die PropertySequence gross genug? + pAccess->checkPropertyArraysSize + ( pAllPropArray, pMapTypeArray, pPropertyConceptArray, rPropCount ); + + // In eigenes Property-Array eintragen + Property& rProp = pAllPropArray[ rPropCount ]; + rProp.Name = aPropName; + rProp.Handle = rPropCount; + rProp.Type = Type( xGetRetType->getTypeClass(), xGetRetType->getName() ); + rProp.Attributes = READONLY; + + // Neuer Eintrag in die Hashtable + rPropNameMap[ aPropName ] = rPropCount; + + // Tabelle fuer XExactName pflegen + rLowerToExactNameMap[ toLower( aPropName ) ] = aPropName; + + // get-Methode merken + pAccess->checkInterfaceArraySize( pAccess->aInterfaceSeq1, + pInterfaces1, rPropCount ); + pInterfaces1[ rPropCount ] = rxMethod_i; + + // Art der Property merken + pMapTypeArray[ rPropCount ] = MAP_GETSET; + pPropertyConceptArray[ rPropCount ] = METHODS; + pAccess->mnMethodPropCount++; + + // Passende set-Methode suchen + sal_Int32 k; + for( k = 0 ; k < nSourceMethodCount ; k++ ) + { + // Methode ansprechen + const Reference<XIdlMethod>& rxMethod_k = pSourceMethods[k]; + + // Nur Methoden nehmen, die nicht schon zugeordnet sind + if( k == i || pMethodTypes[k] != STANDARD_METHOD ) + continue; + + // Name holen und auswerten + OUString aMethName2 = rxMethod_k->getName(); + OUString aStartStr2 = aMethName2.copy( 0, 3 ); + // ACHTUNG: Wegen SDL-Bug NICHT != bei OUString verwenden !!! + if( !( aStartStr2 == OUString( RTL_CONSTASCII_USTRINGPARAM("set")) ) ) + continue; + + // Ist es denn der gleiche Name? + OUString aPropName2 = aMethName2.copy( 3 ); + // ACHTUNG: Wegen SDL-Bug NICHT != bei OUString verwenden !!! + if( !( aPropName == aPropName2 ) ) + continue; + + // set-Methode muss void returnen + Reference<XIdlClass> xSetRetType = rxMethod_k->getReturnType(); + if( xSetRetType->getTypeClass() != TypeClass_VOID ) + { + continue; + } + + // set-Methode darf nur einen Parameter haben + Sequence< Reference<XIdlClass> > setParams = rxMethod_k->getParameterTypes(); + sal_Int32 nParamCount = setParams.getLength(); + if( nParamCount != 1 ) + { + continue; + } + + // Jetzt muss nur noch der return-Typ dem Parameter-Typ entsprechen + const Reference<XIdlClass>* pParamArray2 = setParams.getConstArray(); + Reference<XIdlClass> xParamType = pParamArray2[ 0 ]; + if( xParamType->equals( xGetRetType ) ) + { + pLocalMethodConcepts[ k ] = PROPERTY; + + pMethodTypes[k] = GETSET_METHOD; + + // ReadOnly-Flag wieder loschen + rProp.Attributes &= ~READONLY; + + // set-Methode merken + pAccess->checkInterfaceArraySize( pAccess->aInterfaceSeq2, + pInterfaces2, rPropCount ); + pInterfaces2[ rPropCount ] = rxMethod_k; + } + } + + // Count pflegen + rPropCount++; + } + + // Ist es eine addListener-Methode? + else if( aStartStr == OUString( RTL_CONSTASCII_USTRINGPARAM("add")) ) + { + OUString aListenerStr( RTL_CONSTASCII_USTRINGPARAM("Listener" ) ); + + // Namen der potentiellen Property + sal_Int32 nStrLen = aMethName.getLength(); + sal_Int32 nCopyLen = nStrLen - aListenerStr.getLength(); + OUString aEndStr = aMethName.copy( nCopyLen > 0 ? nCopyLen : 0 ); + + // Endet das Teil auf Listener? + // ACHTUNG: Wegen SDL-Bug NICHT != bei OUString verwenden !!! + if( !( aEndStr == aListenerStr ) ) + continue; + + // Welcher Listener? + OUString aListenerName = aMethName.copy( 3, nStrLen - aListenerStr.getLength() - 3 ); + + // TODO: Hier koennten noch genauere Pruefungen vorgenommen werden + // - Rueckgabe-Typ + // - Anzahl und Art der Parameter + + + // Passende remove-Methode suchen, sonst gilt's nicht + sal_Int32 k; + for( k = 0 ; k < nSourceMethodCount ; k++ ) + { + // Methode ansprechen + const Reference<XIdlMethod>& rxMethod_k = pSourceMethods[k]; + + // Nur Methoden nehmen, die nicht schon zugeordnet sind + if( k == i || pMethodTypes[k] != STANDARD_METHOD ) + continue; + + // Name holen und auswerten + OUString aMethName2 = rxMethod_k->getName(); + sal_Int32 nNameLen = aMethName2.getLength(); + sal_Int32 nCopyLen2 = (nNameLen < 6) ? nNameLen : 6; + OUString aStartStr2 = aMethName2.copy( 0, nCopyLen2 ); + OUString aRemoveStr( RTL_CONSTASCII_USTRINGPARAM("remove" ) ); + // ACHTUNG: Wegen SDL-Bug NICHT != bei OUString verwenden !!! + if( !( aStartStr2 == aRemoveStr ) ) + continue; + + // Ist es denn der gleiche Listener? + if( aMethName2.getLength() - aRemoveStr.getLength() <= aListenerStr.getLength() ) + continue; + OUString aListenerName2 = aMethName2.copy + ( 6, aMethName2.getLength() - aRemoveStr.getLength() - aListenerStr.getLength() ); + // ACHTUNG: Wegen SDL-Bug NICHT != bei OUString verwenden !!! + if( !( aListenerName == aListenerName2 ) ) + continue; + + // TODO: Hier koennten noch genauere Pruefungen vorgenommen werden + // - Rueckgabe-Typ + // - Anzahl und Art der Parameter + + + // Methoden sind als Listener-Schnittstelle erkannt + rMethodConcept_i |= LISTENER; + pLocalMethodConcepts[ k ] |= LISTENER; + + pMethodTypes[i] = ADD_LISTENER_METHOD; + pMethodTypes[k] = REMOVE_LISTENER_METHOD; + nListenerCount++; + } + } + } + + + // Jetzt koennen noch SET-Methoden ohne zugehoerige GET-Methode existieren, + // diese muessen zu Write-Only-Properties gemachte werden. + for( i = 0 ; i < nSourceMethodCount ; i++ ) + { + // Methode ansprechen + const Reference<XIdlMethod>& rxMethod_i = pSourceMethods[i]; + + // Nur Methoden nehmen, die nicht schon zugeordnet sind + if( pMethodTypes[i] != STANDARD_METHOD ) + continue; + + // Namen besorgen + aMethName = rxMethod_i->getName(); + + // Wenn der Name zu kurz ist, wird's sowieso nichts + if( aMethName.getLength() <= 3 ) + continue; + + // Ist es eine set-Methode ohne zugehoerige get-Methode? + aStartStr = aMethName.copy( 0, 3 ); + if( aStartStr == OUString( RTL_CONSTASCII_USTRINGPARAM("set")) ) + { + // Namen der potentiellen Property + aPropName = aMethName.copy( 3 ); + + // set-Methode muss void returnen + Reference<XIdlClass> xSetRetType = rxMethod_i->getReturnType(); + if( xSetRetType->getTypeClass() != TypeClass_VOID ) + { + continue; + } + + // set-Methode darf nur einen Parameter haben + Sequence< Reference<XIdlClass> > setParams = rxMethod_i->getParameterTypes(); + sal_Int32 nParamCount = setParams.getLength(); + if( nParamCount != 1 ) + { + continue; + } + + // Haben wir den Namen schon? + IntrospectionNameMap::iterator aIt = rPropNameMap.find( aPropName ); + if( !( aIt == rPropNameMap.end() ) ) + { + /* TODO: + OSL_TRACE( + String( "Introspection: Property \"" ) + + OOUStringToString( aPropName, CHARSET_SYSTEM ) + + String( "\" found more than once" ) ); + */ + continue; + } + + // Alles klar, es ist eine Write-Only-Property + pLocalMethodConcepts[ i ] = PROPERTY; + + pMethodTypes[i] = GETSET_METHOD; + Reference<XIdlClass> xGetRetType = setParams.getConstArray()[0]; + + // Ist die PropertySequence gross genug? + pAccess->checkPropertyArraysSize + ( pAllPropArray, pMapTypeArray, pPropertyConceptArray, rPropCount ); + + // In eigenes Property-Array eintragen + Property& rProp = pAllPropArray[ rPropCount ]; + rProp.Name = aPropName; + rProp.Handle = rPropCount; + rProp.Type = Type( xGetRetType->getTypeClass(), xGetRetType->getName() ); + rProp.Attributes = 0; // PROPERTY_WRITEONLY ??? + + // Neuer Eintrag in die Hashtable + rPropNameMap[ aPropName ] = rPropCount; + + // Tabelle fuer XExactName pflegen + rLowerToExactNameMap[ toLower( aPropName ) ] = aPropName; + + // set-Methode merken + pAccess->checkInterfaceArraySize( pAccess->aInterfaceSeq2, + pInterfaces2, rPropCount ); + pInterfaces2[ rPropCount ] = rxMethod_i; + + // Art der Property merken + pMapTypeArray[ rPropCount ] = MAP_SETONLY; + pPropertyConceptArray[ rPropCount ] = METHODS; + pAccess->mnMethodPropCount++; + + // Count pflegen + rPropCount++; + } + } + + + //******************************************************************** + + // 4. Methoden in die Gesamt-Sequence uebernehmen + + // Wieviele Methoden muessen in die Method-Sequence? + sal_Int32 nExportedMethodCount = 0; + sal_Int32 nSupportedListenerCount = 0; + for( i = 0 ; i < nSourceMethodCount ; i++ ) + { + if( pMethodTypes[ i ] != INVALID_METHOD ) + { + nExportedMethodCount++; + } + if( pMethodTypes[ i ] == ADD_LISTENER_METHOD ) + { + nSupportedListenerCount++; + } + } + + // Sequences im Access-Objekt entsprechend aufbohren + pAccess->maAllMethodSeq.realloc( nExportedMethodCount + iAllExportedMethod ); + pAccess->maMethodConceptSeq.realloc( nExportedMethodCount + iAllExportedMethod ); + pAccess->maSupportedListenerSeq.realloc( nSupportedListenerCount + iAllSupportedListener ); + + // Methoden reinschreiben + Reference<XIdlMethod>* pDestMethods = pAccess->maAllMethodSeq.getArray(); + sal_Int32* pMethodConceptArray = pAccess->maMethodConceptSeq.getArray(); + Type* pListenerClassRefs = pAccess->maSupportedListenerSeq.getArray(); + for( i = 0 ; i < nSourceMethodCount ; i++ ) + { + if( pMethodTypes[ i ] != INVALID_METHOD ) + { + // Methode ansprechen + const Reference<XIdlMethod>& rxMethod = pSourceMethods[i]; + + // Namen in Hashtable eintragen, wenn nicht schon bekannt + OUString aMethName2 = rxMethod->getName(); + IntrospectionNameMap::iterator aIt = rMethodNameMap.find( aMethName2 ); + if( aIt == rMethodNameMap.end() ) + { + // Eintragen + rMethodNameMap[ aMethName2 ] = iAllExportedMethod; + + // Tabelle fuer XExactName pflegen + rLowerToExactNameMap[ toLower( aMethName2 ) ] = aMethName2; + } + else + { + sal_Int32 iHashResult = (*aIt).second; + + Reference<XIdlMethod> xExistingMethod = pDestMethods[ iHashResult ]; + + Reference< XIdlClass > xExistingMethClass = + xExistingMethod->getDeclaringClass(); + Reference< XIdlClass > xNewMethClass = rxMethod->getDeclaringClass(); + if( xExistingMethClass->equals( xNewMethClass ) ) + continue; + } + + pDestMethods[ iAllExportedMethod ] = rxMethod; + + // Wenn kein Concept gesetzt wurde, ist die Methode "normal" + sal_Int32& rMethodConcept_i = pLocalMethodConcepts[ i ]; + if( !rMethodConcept_i ) + rMethodConcept_i = MethodConcept_NORMAL_IMPL; + pMethodConceptArray[ iAllExportedMethod ] = rMethodConcept_i; + iAllExportedMethod++; + } + if( pMethodTypes[ i ] == ADD_LISTENER_METHOD ) + { + // Klasse des Listeners ermitteln + const Reference<XIdlMethod>& rxMethod = pSourceMethods[i]; + + // void als Default-Klasse eintragen + Reference<XIdlClass> xListenerClass = TypeToIdlClass( getCppuVoidType(), m_xSMgr ); + // ALT: Reference<XIdlClass> xListenerClass = Void_getReflection()->getIdlClass(); + + // 1. Moeglichkeit: Parameter nach einer Listener-Klasse durchsuchen + // Nachteil: Superklassen muessen rekursiv durchsucht werden + Sequence< Reference<XIdlClass> > aParams = rxMethod->getParameterTypes(); + const Reference<XIdlClass>* pParamArray2 = aParams.getConstArray(); + + Reference<XIdlClass> xEventListenerClass = TypeToIdlClass( getCppuType( (Reference<XEventListener>*) NULL ), m_xSMgr ); + // ALT: Reference<XIdlClass> xEventListenerClass = XEventListener_getReflection()->getIdlClass(); + sal_Int32 nParamCount = aParams.getLength(); + sal_Int32 k; + for( k = 0 ; k < nParamCount ; k++ ) + { + const Reference<XIdlClass>& rxClass = pParamArray2[k]; + + // Sind wir von einem Listener abgeleitet? + if( rxClass->equals( xEventListenerClass ) || + isDerivedFrom( rxClass, xEventListenerClass ) ) + { + xListenerClass = rxClass; + break; + } + } + + // 2. Moeglichkeit: Namen der Methode auswerden + // Nachteil: geht nicht bei Test-Listenern, die es nicht gibt + //aMethName = rxMethod->getName(); + //aListenerName = aMethName.Copy( 3, aMethName.Len()-8-3 ); + //Reference<XIdlClass> xListenerClass = reflection->forName( aListenerName ); + Type aListenerType( TypeClass_INTERFACE, xListenerClass->getName() ); + pListenerClassRefs[ iAllSupportedListener ] = aListenerType; + iAllSupportedListener++; + } + } + + // Wenn in diesem Durchlauf XInterface-Methoden + // dabei waren, diese zukuenftig ignorieren + if( bFoundXInterface ) + bXInterfaceIsInvalid = sal_True; + + delete[] pMethodTypes; + delete[] pLocalMethodConcepts; + } + + // Super-Klasse(n) vorhanden? Dann dort fortsetzen + Sequence< Reference<XIdlClass> > aSuperClassSeq = xImplClass2->getSuperclasses(); + + // Zur Zeit wird nur von einer Superklasse ausgegangen + if( aSuperClassSeq.getLength() >= 1 ) + { + xImplClass2 = aSuperClassSeq.getConstArray()[0]; + OSL_ENSURE( xImplClass2.is(), "super class null" ); + } + else + { + xImplClass2 = NULL; + } + } + } + + // Anzahl der exportierten Methoden uebernehmen und Sequences anpassen + // (kann abweichen, weil doppelte Methoden erst nach der Ermittlung + // von nExportedMethodCount herausgeworfen werden) + sal_Int32& rMethCount = pAccess->mnMethCount; + rMethCount = iAllExportedMethod; + pAccess->maAllMethodSeq.realloc( rMethCount ); + pAccess->maMethodConceptSeq.realloc( rMethCount ); + + // Groesse der Property-Sequences anpassen + pAccess->maAllPropertySeq.realloc( rPropCount ); + pAccess->maPropertyConceptSeq.realloc( rPropCount ); + pAccess->maMapTypeSeq.realloc( rPropCount ); + + // Ende der Schleife ueber alle vom ClassProvider angegebenen Klassen + } + } + // Bei structs Fields als Properties registrieren + else //if( eType == TypeClass_STRUCT ) + { + // Ist es ein Interface oder eine struct? + //Reference<XIdlClass> xClassRef = aToInspectObj.getReflection()->getIdlClass(); + Reference<XIdlClass> xClassRef = TypeToIdlClass( aToInspectObj.getValueType(), m_xSMgr ); + if( !xClassRef.is() ) + { + OSL_FAIL( "Can't get XIdlClass from Reflection" ); + return pAccess; + } + + // Felder holen + Sequence< Reference<XIdlField> > fields = xClassRef->getFields(); + const Reference<XIdlField>* pFields = fields.getConstArray(); + sal_Int32 nLen = fields.getLength(); + + for( i = 0 ; i < nLen ; i++ ) + { + Reference<XIdlField> xField = pFields[i]; + Reference<XIdlClass> xPropType = xField->getType(); + OUString aPropName = xField->getName(); + + // Ist die PropertySequence gross genug? + pAccess->checkPropertyArraysSize + ( pAllPropArray, pMapTypeArray, pPropertyConceptArray, rPropCount ); + + // In eigenes Property-Array eintragen + Property& rProp = pAllPropArray[ rPropCount ]; + rProp.Name = aPropName; + rProp.Handle = rPropCount; + rProp.Type = Type( xPropType->getTypeClass(), xPropType->getName() ); + FieldAccessMode eAccessMode = xField->getAccessMode(); + rProp.Attributes = (eAccessMode == FieldAccessMode_READONLY || + eAccessMode == FieldAccessMode_CONST) + ? READONLY : 0; + + //FieldAccessMode eAccessMode = xField->getAccessMode(); + //rProp.Attributes = (eAccessMode == FieldAccessMode::READONLY || eAccessMode == CONST) + //? PropertyAttribute::READONLY : 0; + + // Namen in Hashtable eintragen + rPropNameMap[ aPropName ] = rPropCount; + + // Tabelle fuer XExactName pflegen + rLowerToExactNameMap[ toLower( aPropName ) ] = aPropName; + + // Field merken + pAccess->checkInterfaceArraySize( pAccess->aInterfaceSeq1, + pInterfaces1, rPropCount ); + pInterfaces1[ rPropCount ] = xField; + + // Art der Property merken + pMapTypeArray[ rPropCount ] = MAP_FIELD; + pPropertyConceptArray[ rPropCount ] = ATTRIBUTES; + pAccess->mnAttributePropCount++; + + // Count pflegen + rPropCount++; + } + } + + // Property-Sequence auf die richtige Laenge bringen + pAccess->maAllPropertySeq.realloc( pAccess->mnPropCount ); + + return pAccess; +} + +//************************************************************************* +Reference< XInterface > SAL_CALL ImplIntrospection_CreateInstance( const Reference< XMultiServiceFactory > & rSMgr ) + throw( RuntimeException ) +{ + Reference< XInterface > xService = (OWeakObject*)(OComponentHelper*)new ImplIntrospection( rSMgr ); + return xService; +} + +} + +extern "C" +{ +//================================================================================================== +void SAL_CALL component_getImplementationEnvironment( + const sal_Char ** ppEnvTypeName, uno_Environment ** ) +{ + *ppEnvTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME; +} +//================================================================================================== +void * SAL_CALL component_getFactory( + const sal_Char * pImplName, void * pServiceManager, void * ) +{ + void * pRet = 0; + + if (pServiceManager && rtl_str_compare( pImplName, IMPLEMENTATION_NAME ) == 0) + { + Reference< XSingleServiceFactory > xFactory( createOneInstanceFactory( + reinterpret_cast< XMultiServiceFactory * >( pServiceManager ), + OUString::createFromAscii( pImplName ), + stoc_inspect::ImplIntrospection_CreateInstance, + stoc_inspect::ImplIntrospection::getSupportedServiceNames_Static() ) ); + + if (xFactory.is()) + { + xFactory->acquire(); + pRet = xFactory.get(); + } + } + + return pRet; +} +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |