/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
// Special value for Method-Concept, to be able to mark "normal" functions #define MethodConcept_NORMAL_IMPL 0x80000000
// Method to assert, if a class is derived from another class bool isDerivedFrom( const Reference<XIdlClass>& xToTestClass, const Reference<XIdlClass>& xDerivedFromClass )
{ const Sequence< Reference<XIdlClass> > aClassesSeq = xToTestClass->getSuperclasses();
// *** Classification of Properties (no enum, to be able to use Sequence) *** // Properties from a PropertySet-Interface #define MAP_PROPERTY_SET 0 // Properties from Fields #define MAP_FIELD 1 // Properties that get described with get/set methods #define MAP_GETSET 2 // Properties with only a set method #define MAP_SETONLY 3
// Increments by which the size of sequences get adjusted #define ARRAY_SIZE_STEP 20
//*** IntrospectionAccessStatic_Impl ***
// Equals to the old IntrospectionAccessImpl, forms now a static // part of the new Instance-related ImplIntrospectionAccess
// Hashtable for the search of names typedef std::unordered_map
<
OUString,
sal_Int32
>
IntrospectionNameMap;
// Hashtable to assign exact names to the Lower-Case // converted names, for the support of XExactName typedef std::unordered_map
<
OUString,
OUString
>
LowerToExactNameMap;
class IntrospectionAccessStatic_Impl: public salhelper::SimpleReferenceObject
{ friendclass Implementation; friendclass ImplIntrospectionAccess;
// InterfaceSequences, to save additional information in a property // for example the Field at MAP_FIELD, the get/set-Methods at MAP_GETSET, et cetera
std::vector< Reference<XInterface> > aInterfaceSeq1;
std::vector< Reference<XInterface> > aInterfaceSeq2;
// Hashtables for names
IntrospectionNameMap maPropertyNameMap;
IntrospectionNameMap maMethodNameMap;
LowerToExactNameMap maLowerToExactNameMap;
// Vector of all Properties, also for delivering from getProperties()
std::vector<Property> maAllPropertySeq;
// Mapping of properties to Access-Types
std::vector<sal_Int16> maMapTypeSeq;
// Classification of found methods
std::vector<sal_Int32> maPropertyConceptSeq;
// Number of Properties
sal_Int32 mnPropCount;
// Number of Properties, which are assigned to particular concepts //sal_Int32 mnDangerousPropCount;
sal_Int32 mnPropertySetPropCount;
sal_Int32 mnAttributePropCount;
sal_Int32 mnMethodPropCount;
// Flags which indicate if various interfaces are present bool mbFastPropSet; bool mbElementAccess; bool mbNameAccess; bool mbNameReplace; bool mbNameContainer; bool mbIndexAccess; bool mbIndexReplace; bool mbIndexContainer; bool mbEnumerationAccess; bool mbIdlArray; bool mbUnoTunnel;
// Original handles of FastPropertySets
std::unique_ptr<sal_Int32[]> mpOrgPropertyHandleArray;
// MethodSequence, that accepts all methods
std::vector< Reference<XIdlMethod> > maAllMethodSeq;
// Classification of found methods
std::vector<sal_Int32> maMethodConceptSeq;
// Number of methods
sal_Int32 mnMethCount;
// Sequence of Listener, that can be registered
std::vector< Type > maSupportedListenerSeq;
sal_Int32 IntrospectionAccessStatic_Impl::getPropertyIndex( const OUString& aPropertyName ) const
{ auto aIt = maPropertyNameMap.find(aPropertyName); if (aIt != maPropertyNameMap.end()) return aIt->second;
return -1;
}
sal_Int32 IntrospectionAccessStatic_Impl::getMethodIndex( const OUString& aMethodName ) const
{ auto aIt = maMethodNameMap.find(aMethodName); if (aIt != maMethodNameMap.end())
{ return aIt->second;
}
// #95159 Check if full qualified name matches
sal_Int32 nSearchFrom = aMethodName.getLength(); while( true )
{ // Strategy: Search back until the first '_' is found
sal_Int32 nFound = aMethodName.lastIndexOf( '_', nSearchFrom ); if( nFound == -1 ) break;
aIt = maMethodNameMap.find( aPureMethodName ); if (aIt != 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 const sal_Int32 iHashResult = aIt->second;
Reference< XIdlClass > xMethClass = xMethod->getDeclaringClass(); if( xClass->equals( xMethClass ) )
{ return iHashResult;
} else
{ // Could also be another method with the same name // Iterate over all methods
size_t nLen = maAllMethodSeq.size(); for (size_t i = 0; i < nLen; ++i)
{ const Reference<XIdlMethod> xMethod2 = maAllMethodSeq[ i ]; if( xMethod2->getName() == aPureMethodName )
{
Reference< XIdlClass > xMethClass2 = xMethod2->getDeclaringClass();
// New Impl class as part of the introspection conversion to instance-bound // Introspection with property access via XPropertySet. The old class // ImplIntrospectionAccess lives on as IntrospectionAccessStatic_Impl class ImplIntrospectionAccess : public IntrospectionAccessHelper
{ friendclass Implementation;
// Object under examination
Any maInspectedObject;
// As interface
Reference<XInterface> mxIface;
// Static introspection data
rtl::Reference< IntrospectionAccessStatic_Impl > mpStaticImpl;
// Last Sequence that came with getProperties (optimization)
Sequence<Property> maLastPropertySeq;
sal_Int32 mnLastPropertyConcept;
// Last Sequence that came with getMethods (optimization)
Sequence<Reference<XIdlMethod> > maLastMethodSeq;
sal_Int32 mnLastMethodConcept;
// Guards the caching of queried interfaces
std::mutex m_aMutex;
// Original interfaces of the objects
Reference<XElementAccess> mxObjElementAccess;
Reference<XNameContainer> mxObjNameContainer;
Reference<XNameReplace> mxObjNameReplace;
Reference<XNameAccess> mxObjNameAccess;
Reference<XIndexContainer> mxObjIndexContainer;
Reference<XIndexReplace> mxObjIndexReplace;
Reference<XIndexAccess> mxObjIndexAccess;
Reference<XEnumerationAccess> mxObjEnumerationAccess;
Reference<XIdlArray> mxObjIdlArray;
// Realloc sequence according to the required number
maLastPropertySeq.realloc( nCount );
Property* pDestProps = maLastPropertySeq.getArray();
// Go through all the properties and apply according to the concept const std::vector<Property>& rPropSeq = mpStaticImpl->getProperties(); const std::vector<sal_Int32>& rConcepts = mpStaticImpl->getPropertyConcepts();
sal_Int32 nLen = static_cast<sal_Int32>(rPropSeq.size());
sal_Int32 iDest = 0; for( sal_Int32 i = 0 ; i < nLen ; i++ )
{
sal_Int32 nConcept = rConcepts[ i ]; if( nConcept & PropertyConcepts )
pDestProps[ iDest++ ] = rPropSeq[ i ];
}
// Realloc sequence according to the required number // Unlike Properties, the number can not be determined by counters in // inspect() beforehand, since methods can belong to several concepts
maLastMethodSeq.realloc( nLen );
Reference<XIdlMethod>* pDestMethods = maLastMethodSeq.getArray();
// Go through all the methods and apply according to the concept
sal_Int32 iDest = 0; for( sal_Int32 i = 0 ; i < nLen ; i++ )
{
sal_Int32 nConcept = mpStaticImpl->getMethodConcepts()[ i ]; if( nConcept & MethodConcepts )
pDestMethods[ iDest++ ] = aMethodSeq[ i ];
}
// Bring to the correct length
maLastMethodSeq.realloc( iDest );
// Methods from XMaterialHolder
Any ImplIntrospectionAccess::getMaterial()
{ return maInspectedObject;
}
// Methods from XExactName
OUString ImplIntrospectionAccess::getExactName( const OUString& rApproximateName )
{
OUString aRetStr;
LowerToExactNameMap::iterator aIt =
mpStaticImpl->maLowerToExactNameMap.find( rApproximateName.toAsciiLowerCase() ); if (aIt != mpStaticImpl->maLowerToExactNameMap.end())
aRetStr = (*aIt).second; return aRetStr;
}
struct TypeKey {
TypeKey(
css::uno::Reference<css::beans::XPropertySetInfo> theProperties,
std::vector<css::uno::Type> const & theTypes):
properties(std::move(theProperties))
{ //TODO: Could even sort the types lexicographically first, to increase // the chance of matches between different implementations' getTypes(), // but the old scheme of using getImplementationId() would have missed // those matches, too:
OUStringBuffer b(static_cast<int>(theTypes.size() * 64)); for (const css::uno::Type& rType : theTypes) {
b.append(rType.getTypeName()
+ "*"); // arbitrary delimiter not used by type grammar
}
types = b.makeStringAndClear();
}
// For a FastPropertySet we must remember the original handles if( bFast )
pAccess->mpOrgPropertyHandleArray.reset( new sal_Int32[ nLen ] );
for( sal_Int32 i = 0 ; i < nLen ; i++ )
{ // Put property in its own list
pAccess->checkPropertyArraysSize( rPropCount );
Property& rProp = rAllPropArray[ rPropCount ];
rProp = pProps[ i ];
if( bFast )
pAccess->mpOrgPropertyHandleArray[ i ] = rProp.Handle;
// Enter PropCount as a handle for its own FastPropertySet
rProp.Handle = rPropCount;
// Remember type of property
rMapTypeArray[ rPropCount ] = MAP_PROPERTY_SET;
rPropertyConceptArray[ rPropCount ] = PROPERTYSET;
pAccess->mnPropertySetPropCount++;
// Enter name in hash table if not already known
OUString aPropName = rProp.Name;
// Do we already have the name?
IntrospectionNameMap::iterator aIt = rPropNameMap.find( aPropName ); if( aIt == rPropNameMap.end() )
{ // New entry in the hash table
rPropNameMap[ aPropName ] = rPropCount;
// Maintain table for XExactName
rLowerToExactNameMap[ aPropName.toAsciiLowerCase() ] = aPropName;
} else
{
SAL_WARN( "stoc", "Introspection: Property \"" <<
aPropName << "\" found more than once in PropertySet" );
}
// Adjust count
rPropCount++;
}
}
// Indices in the export table
sal_Int32 iAllExportedMethod = 0;
sal_Int32 iAllSupportedListener = 0;
std::set<OUString> seen;
// Flag, whether XInterface methods should be recorded // (this must be done only once, allowed initially) bool bXInterfaceIsInvalid = false;
// Flag whether the XInterface methods have already been recorded. If // sal_True, bXInterfaceIsInvalid is activated at the end of the interface // loop, and XInterface methods are cut off thereafter. bool bFoundXInterface = false;
// Remember type of property
rMapTypeArray[ rPropCount ] = MAP_FIELD;
rPropertyConceptArray[ rPropCount ] = ATTRIBUTES;
pAccess->mnAttributePropCount++;
// Adjust count
rPropCount++;
}
// 3. Methods
// Get and remember all methods
Sequence< Reference<XIdlMethod> > methods = rxIfaceClass->getMethods(); const Reference<XIdlMethod>* pSourceMethods = methods.getConstArray();
sal_Int32 nSourceMethodCount = methods.getLength();
// 3. a) Search get/set and listener methods
// Create field for information about the methods, so that methods which are not // related to properties or listeners can easily be found later. // New: initialise MethodConceptArray enum MethodType
{
STANDARD_METHOD, // normal method, not related to properties or listeners
GETSET_METHOD, // belongs to a get/set property
ADD_LISTENER_METHOD, // add method of a listener interface
REMOVE_LISTENER_METHOD, // remove method of a listener interface
INVALID_METHOD // method whose class is not considered, e.g. XPropertySet
};
std::unique_ptr<MethodType[]> pMethodTypes( new MethodType[ nSourceMethodCount ] );
std::unique_ptr<sal_Int32[]> pLocalMethodConcepts( new sal_Int32[ nSourceMethodCount ] ); for( sal_Int32 i = 0 ; i < nSourceMethodCount ; i++ )
{
pMethodTypes[ i ] = STANDARD_METHOD;
pLocalMethodConcepts[ i ] = 0;
}
for( sal_Int32 i = 0 ; i < nSourceMethodCount ; i++ )
{ // Address method const Reference<XIdlMethod>& rxMethod_i = pSourceMethods[i];
sal_Int32& rMethodConcept_i = pLocalMethodConcepts[ i ];
// Fetch name
OUString aMethName = rxMethod_i->getName();
// Catalogue methods // Filter all (?) methods of XInterface so e.g. acquire and release // can not be called from scripting
OUString className(
rxMethod_i->getDeclaringClass()->getName()); if (className == "com.sun.star.uno.XInterface") {
bFoundXInterface = true;
// If the name is too short, it isn't anything if( aMethName.getLength() <= 3 ) continue;
// Is it a get method?
OUString aPropName; if( aMethName.startsWith("get", &aPropName) )
{ // Get methods must not have any parameters
Sequence< Reference<XIdlClass> > getParams = rxMethod_i->getParameterTypes(); if( getParams.hasElements() )
{ continue;
}
// Do we have the name already?
IntrospectionNameMap::iterator aIt = rPropNameMap.find( aPropName ); if (aIt != rPropNameMap.end())
{ /* TODO SAL_INFO("stoc",( String( "Introspection: Property \"" ) + OOUStringToString( aPropName, CHARSET_SYSTEM ) + String( "\" found more than once" ) );
*/ continue;
}
// It is already at least a read-only property
rMethodConcept_i |= PROPERTY;
// Remember type of property
rMapTypeArray[ rPropCount ] = MAP_GETSET;
rPropertyConceptArray[ rPropCount ] = METHODS;
pAccess->mnMethodPropCount++;
// Search for matching set method
sal_Int32 k; for( k = 0 ; k < nSourceMethodCount ; k++ )
{ // Address method const Reference<XIdlMethod>& rxMethod_k = pSourceMethods[k];
// Accept only methods that are not already assigned if( k == i || pMethodTypes[k] != STANDARD_METHOD ) continue;
// Get name and evaluate
OUString aMethName2 = rxMethod_k->getName();
std::u16string_view aPropName2; if (!(aMethName2.startsWith("set", &aPropName2)
&& aPropName2 == aPropName)) continue;
// A set method must return void
Reference<XIdlClass> xSetRetType = rxMethod_k->getReturnType(); if( xSetRetType->getTypeClass() != TypeClass_VOID )
{ continue;
}
// A set method may only have one parameter
Sequence< Reference<XIdlClass> > setParams = rxMethod_k->getParameterTypes();
sal_Int32 nParamCount = setParams.getLength(); if( nParamCount != 1 )
{ continue;
}
// Next, the return type must correspond to the parameter type const Reference<XIdlClass>* pParamArray2 = setParams.getConstArray();
Reference<XIdlClass> xParamType = pParamArray2[ 0 ]; if( xParamType->equals( xGetRetType ) )
{
pLocalMethodConcepts[ k ] = PROPERTY;
pMethodTypes[k] = GETSET_METHOD;
// Delete read-only flag again
rProp.Attributes &= ~READONLY;
// Is it an add listener method? elseif( aMethName.startsWith("add", &aPropName) )
{ // Does it end with "Listener"?
std::u16string_view aListenerName; if( !aPropName.endsWith("Listener", &aListenerName) ) continue;
// TODO: More accurate tests could still be carried out here // - Return type // - Number and type of parameters
// Search for matching remove method, otherwise not applicable
sal_Int32 k; for( k = 0 ; k < nSourceMethodCount ; k++ )
{ // Address method const Reference<XIdlMethod>& rxMethod_k = pSourceMethods[k];
// Accept only methods that are not already assigned if( k == i || pMethodTypes[k] != STANDARD_METHOD ) continue;
// Get name and evaluate
OUString aMethName2 = rxMethod_k->getName();
std::u16string_view rest;
std::u16string_view aListenerName2; if (!(aMethName2.startsWith( "remove", &rest)
&& o3tl::ends_with(rest,
u"Listener", &aListenerName2)
&& aListenerName2 == aListenerName)) continue;
// TODO: More accurate tests could still be carried out here // - Return type // - Number and type of parameters
// Methods are recognised as a listener interface
rMethodConcept_i |= LISTENER;
pLocalMethodConcepts[ k ] |= LISTENER;
// A set method could still exist without a corresponding get method, // this must be a write-only property for( sal_Int32 i = 0 ; i < nSourceMethodCount ; i++ )
{ // Address method const Reference<XIdlMethod>& rxMethod_i = pSourceMethods[i];
// Accept only methods that are not already assigned if( pMethodTypes[i] != STANDARD_METHOD ) continue;
// Get name
OUString aMethName = rxMethod_i->getName();
// If the name is too short, it isn't anything if( aMethName.getLength() <= 3 ) continue;
// Is it a set method without associated get method?
OUString aPropName; if( aMethName.startsWith("set", &aPropName) )
{ // A set method must return void
Reference<XIdlClass> xSetRetType = rxMethod_i->getReturnType(); if( xSetRetType->getTypeClass() != TypeClass_VOID )
{ continue;
}
// A set method may only have one parameter
Sequence< Reference<XIdlClass> > setParams = rxMethod_i->getParameterTypes();
sal_Int32 nParamCount = setParams.getLength(); if( nParamCount != 1 )
{ continue;
}
// Do we have the name already?
IntrospectionNameMap::iterator aIt = rPropNameMap.find( aPropName ); if (aIt != rPropNameMap.end())
{ /* TODO: SAL_INFO("stoc",( String( "Introspection: Property \"" ) + OOUStringToString( aPropName, CHARSET_SYSTEM ) + String( "\" found more than once" ) );
*/ continue;
}
// Now we know it's a write only property
pLocalMethodConcepts[ i ] = PROPERTY;
// Write in methods for( sal_Int32 i = 0 ; i < nSourceMethodCount ; i++ )
{ if( pMethodTypes[ i ] != INVALID_METHOD )
{ // Address method const Reference<XIdlMethod>& rxMethod = pSourceMethods[i];
// Enter name in hash table if not already known
OUString aMethName2 = rxMethod->getName();
IntrospectionNameMap::iterator aIt = rMethodNameMap.find( aMethName2 ); if( aIt == rMethodNameMap.end() )
{ // Enter
rMethodNameMap[ aMethName2 ] = iAllExportedMethod;
// If a concept has been set, is the method "normal"?
sal_Int32& rMethodConcept_i = pLocalMethodConcepts[ i ]; if( !rMethodConcept_i )
rMethodConcept_i = MethodConcept_NORMAL_IMPL;
pAccess->maMethodConceptSeq[ iAllExportedMethod ] = rMethodConcept_i;
iAllExportedMethod++;
} if( pMethodTypes[ i ] == ADD_LISTENER_METHOD )
{ // Determine class of listener const Reference<XIdlMethod>& rxMethod = pSourceMethods[i];
// Enter void as default class
css::uno::Reference<css::reflection::XIdlClass>
xListenerClass(
reflection->forName(
cppu::UnoType<void>::get()
.getTypeName())); // Old: Reference<XIdlClass> xListenerClass = Void_getReflection()->getIdlClass();
// Option 1: Search for parameters for a listener class // Disadvantage: Superclasses should be searched recursively const Sequence< Reference<XIdlClass> > aParams = rxMethod->getParameterTypes();
css::uno::Reference<css::reflection::XIdlClass>
xEventListenerClass(
reflection->forName(
cppu::UnoType<
css::lang::XEventListener>::get()
.getTypeName())); // Old: Reference<XIdlClass> xEventListenerClass = XEventListener_getReflection()->getIdlClass(); auto pParam = std::find_if(aParams.begin(), aParams.end(),
[&xEventListenerClass](const Reference<XIdlClass>& rxClass) { // Are we derived from a listener? return rxClass->equals( xEventListenerClass )
|| isDerivedFrom( rxClass, xEventListenerClass );
}); if (pParam != aParams.end())
{
xListenerClass = *pParam;
}
// Option 2: Unload the name of the method // Disadvantage: Does not work with test listeners, where it does not exist //aMethName = rxMethod->getName(); //aListenerName = aMethName.Copy( 3, aMethName.Len()-8-3 ); //Reference<XIdlClass> xListenerClass = reflection->forName( aListenerName );
pAccess->maSupportedListenerSeq[ iAllSupportedListener ] =
Type(TypeClass_INTERFACE, xListenerClass->getName());
iAllSupportedListener++;
}
}
// When there were XInterface methods in this run, // ignore them in the future if( bFoundXInterface )
bXInterfaceIsInvalid = true;
}
// Do superclasses exist? Then continue here
Sequence< Reference<XIdlClass> > aSuperClassSeq = xImplClass2->getSuperclasses();
// Currently only one superclass is considered if( aSuperClassSeq.getLength() >= 1 )
{
xImplClass2 = aSuperClassSeq.getConstArray()[0];
OSL_ENSURE( xImplClass2.is(), "super class null" );
} else
{
xImplClass2 = nullptr;
}
}
}
// Apply number of exported methods and adapt Sequences // (can be different because duplicate methods are thrown // out only after the determination of nExportedMethodCount)
sal_Int32& rMethCount = pAccess->mnMethCount;
rMethCount = iAllExportedMethod;
pAccess->maAllMethodSeq.resize( rMethCount );
pAccess->maMethodConceptSeq.resize( rMethCount );
// Resize the property sequences
pAccess->maAllPropertySeq.resize( rPropCount );
pAccess->maPropertyConceptSeq.resize( rPropCount );
pAccess->maMapTypeSeq.resize( rPropCount );
} // Register struct fields as properties else//if( eType == TypeClass_STRUCT )
{ // Is it an interface or a struct? //Reference<XIdlClass> xClassRef = aToInspectObj.getReflection()->getIdlClass();
css::uno::Reference<css::reflection::XIdlClass> xClassRef(
reflection->forName(aToInspectObj.getValueTypeName())); if( !xClassRef.is() )
{
SAL_WARN( "stoc", "Can't get XIdlClass from Reflection" ); returnnew ImplIntrospectionAccess(aToInspectObj, pAccess);
}
// Get fields const Sequence< Reference<XIdlField> > fields = xClassRef->getFields();
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.41Bemerkung:
(vorverarbeitet am 2026-05-08)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.