1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: macmgr.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 #include "rtl/ustrbuf.hxx"
32 #include "rtl/strbuf.hxx"
34 #include "plugin/impl.hxx"
36 #include "osl/module.hxx"
40 using namespace com::sun::star::uno
;
41 using namespace com::sun::star::plugin
;
43 namespace plugstringhelper
46 rtl::OUString
getString( CFStringRef i_xString
)
48 rtl::OUStringBuffer aBuf
;
51 CFIndex nChars
= CFStringGetLength( i_xString
);
52 CFRange aRange
= { 0, nChars
};
53 aBuf
.setLength( nChars
);
54 CFStringGetCharacters( i_xString
, aRange
, static_cast< UniChar
* >(const_cast<sal_Unicode
*>(aBuf
.getStr())) );
56 return aBuf
.makeStringAndClear();
59 rtl::OUString
getString( CFURLRef i_xURL
)
61 CFStringRef xString
= CFURLGetString( i_xURL
);
62 return getString( xString
);
65 CFMutableStringRef
createString( const rtl::OUString
& i_rString
)
67 CFMutableStringRef xString
= CFStringCreateMutable( NULL
, 0 );
69 CFStringAppendCharacters( xString
, i_rString
.getStr(), i_rString
.getLength() );
73 CFURLRef
createURL( const rtl::OUString
& i_rString
)
76 CFMutableStringRef xMutableString
= createString( i_rString
);
77 CFURLRef xURL
= CFURLCreateWithString( NULL
, xMutableString
, NULL
);
78 CFRelease( xMutableString
);
82 rtl::OUString
getURLFromPath( const rtl::OUString
& i_rPath
)
84 CFMutableStringRef xMutableString
= createString( i_rPath
);
85 CFURLRef xURL
= CFURLCreateWithFileSystemPath( NULL
, xMutableString
, kCFURLPOSIXPathStyle
, true );
86 CFRelease( xMutableString
);
87 CFStringRef xString
= CFURLGetString( xURL
);
88 rtl::OUString aRet
= getString( xString
);
93 CFURLRef
createURLFromPath( const rtl::OUString
& i_rPath
)
95 CFMutableStringRef xMutableString
= createString( i_rPath
);
96 CFURLRef xURL
= CFURLCreateWithFileSystemPath( NULL
, xMutableString
, kCFURLPOSIXPathStyle
, true );
100 rtl::OUString
CFURLtoOSLURL( CFURLRef i_xURL
)
103 CFURLRef xAbsURL
= CFURLCopyAbsoluteURL( i_xURL
);
105 CFStringRef xSysPath
= CFURLCopyFileSystemPath( xAbsURL
? xAbsURL
: i_xURL
, kCFURLPOSIXPathStyle
);
107 CFRelease( xAbsURL
);
108 rtl::OUString
aSysPath( getString( xSysPath
) );
109 CFRelease( xSysPath
);
110 rtl::OUString aFileURL
;
111 osl_getFileURLFromSystemPath( aSysPath
.pData
, &aFileURL
.pData
);
117 using namespace plugstringhelper
;
119 static int parsePlist( CFBundleRef i_xBundle
, const rtl::OUString
& i_rBundleURL
, list
< PluginDescription
* >& io_rDescriptions
)
121 CFTypeRef xMimeDict
= CFBundleGetValueForInfoDictionaryKey( i_xBundle
, CFSTR("WebPluginMIMETypes"));
123 if( xMimeDict
== 0 ||
124 CFGetTypeID(xMimeDict
) != CFDictionaryGetTypeID() ||
125 (nMimetypes
= CFDictionaryGetCount( static_cast<CFDictionaryRef
>(xMimeDict
))) <= 0 )
130 // prepare an array of key and value refs
131 std::vector
< CFTypeRef
> aKeys( nMimetypes
, CFTypeRef(NULL
) );
132 std::vector
< CFTypeRef
> aValues( nMimetypes
, CFTypeRef(NULL
) );
133 CFDictionaryGetKeysAndValues(static_cast<CFDictionaryRef
>(xMimeDict
), &aKeys
[0], &aValues
[0] );
136 for( int i
= 0; i
< nMimetypes
; i
++ )
139 CFTypeRef xKey
= aKeys
[i
];
140 if( ! xKey
|| CFGetTypeID(xKey
) != CFStringGetTypeID() )
142 rtl::OUString aMimetype
= getString( (CFStringRef
)xKey
);
144 // the correspoding value should be a dictionary
145 CFTypeRef xDict
= aValues
[i
];
146 if( ! xDict
|| CFGetTypeID( xDict
) != CFDictionaryGetTypeID() )
149 // get the extension list
150 CFTypeRef xExtArray
= CFDictionaryGetValue( (CFDictionaryRef
)xDict
, CFSTR("WebPluginExtensions" ) );
151 if( !xExtArray
|| CFGetTypeID( xExtArray
) != CFArrayGetTypeID() )
154 OUStringBuffer aExtBuf
;
155 int nExtensions
= CFArrayGetCount( (CFArrayRef
)xExtArray
);
156 for( int n
= 0; n
< nExtensions
; n
++ )
158 CFTypeRef xExt
= CFArrayGetValueAtIndex( (CFArrayRef
)xExtArray
, n
);
159 if( xExt
&& CFGetTypeID( xExt
) == CFStringGetTypeID() )
161 if( aExtBuf
.getLength() > 0 )
162 aExtBuf
.append( sal_Unicode(';') );
163 OUString
aExt( getString( (CFStringRef
)xExt
) );
164 if( aExt
.indexOfAsciiL( "*.", 2 ) != 0 )
165 aExtBuf
.appendAscii( "*." );
166 aExtBuf
.append( aExt
);
170 // get the description string
171 CFTypeRef xDescString
= CFDictionaryGetValue( (CFDictionaryRef
)xDict
, CFSTR("WebPluginTypeDescription" ) );
172 if( !xDescString
|| CFGetTypeID( xDescString
) != CFStringGetTypeID() )
174 rtl::OUString aDescription
= getString( (CFStringRef
)xDescString
);
176 PluginDescription
* pNew
= new PluginDescription
;
177 // set plugin name (path to library)
178 pNew
->PluginName
= i_rBundleURL
;
180 pNew
->Mimetype
= aMimetype
;
181 // set extension line
182 pNew
->Extension
= aExtBuf
.makeStringAndClear();
184 pNew
->Description
= aDescription
;
186 io_rDescriptions
.push_back( pNew
);
189 #if OSL_DEBUG_LEVEL > 1
191 "Inserting from PList:\n"
194 " Description: %s\n",
195 OUStringToOString( pNew
->Mimetype
, RTL_TEXTENCODING_UTF8
).getStr(),
196 OUStringToOString( pNew
->Extension
, RTL_TEXTENCODING_UTF8
).getStr(),
197 OUStringToOString( pNew
->Description
, RTL_TEXTENCODING_UTF8
).getStr()
206 static int parseMimeString( const rtl::OUString
& i_rBundleURL
, list
< PluginDescription
* >& io_rDescriptions
, const char* i_pMime
)
211 rtl_TextEncoding aEncoding
= osl_getThreadTextEncoding();
214 aMIME
.append( i_pMime
);
216 if( aMIME
.getLength() < 1 )
219 OString aLine
= aMIME
.makeStringAndClear();
222 sal_Int32 nIndex
= 0;
223 while( nIndex
!= -1 )
225 OString aType
= aLine
.getToken( 0, ';', nIndex
);
227 sal_Int32 nTypeIndex
= 0;
228 OString aMimetype
= aType
.getToken( 0, ':', nTypeIndex
);
229 OString aExtLine
= aType
.getToken( 0, ':', nTypeIndex
);
230 if( nTypeIndex
< 0 ) // ensure at least three tokens
232 OString aDesc
= aType
.getToken( 0, ':', nTypeIndex
);
234 // create extension list string
235 sal_Int32 nExtIndex
= 0;
236 OStringBuffer aExtension
;
237 while( nExtIndex
!= -1 )
239 OString aExt
= aExtLine
.getToken( 0, ',', nExtIndex
);
240 if( aExt
.indexOf( "*." ) != 0 )
241 aExtension
.append( "*." );
242 aExtension
.append( aExt
);
243 if( nExtIndex
!= -1 )
244 aExtension
.append( ';' );
247 PluginDescription
* pNew
= new PluginDescription
;
248 // set plugin name (path to library)
249 pNew
->PluginName
= i_rBundleURL
;
251 pNew
->Mimetype
= OStringToOUString( aMimetype
, aEncoding
);
252 // set extension line
253 pNew
->Extension
= OStringToOUString( aExtension
.makeStringAndClear(), aEncoding
);
255 pNew
->Description
= OStringToOUString( aDesc
, aEncoding
);
256 io_rDescriptions
.push_back( pNew
);
259 #if OSL_DEBUG_LEVEL > 1
261 "Inserting from mime string:\n"
264 " Description: %s\n",
265 OUStringToOString( pNew
->Mimetype
, aEncoding
).getStr(),
266 OUStringToOString( pNew
->Extension
, aEncoding
).getStr(),
267 OUStringToOString( pNew
->Description
, aEncoding
).getStr()
274 // this is so ugly it you want to tear your eyes out
275 static rtl::OUString
GetNextPluginStringFromHandle(Handle h
, short *index
)
277 char* pPascalBytes
= (*h
+ *index
);
278 sal_uInt32 nLen
= (unsigned char)pPascalBytes
[0];
279 rtl::OStringBuffer
aBuf( nLen
);
280 aBuf
.append( pPascalBytes
+1, nLen
);
282 return rtl::OStringToOUString( aBuf
.makeStringAndClear(), RTL_TEXTENCODING_UTF8
);
285 static int parseMimeResource( CFBundleRef i_xBundle
,
287 const rtl::OUString
& i_rBundleURL
,
288 list
< PluginDescription
* >& io_rDescriptions
)
291 // just to hurt our eyes more there is an alternative mimetype function plus the possibility
292 // of a resource fork. Must be a case of think different.
299 BPSupportedMIMETypes aMIMETypesStrangeStruct
= {kBPSupportedMIMETypesStructVers_1
, NULL
, NULL
};
301 BP_GetSupportedMIMETypesUPP pBPGetSupp
= (BP_GetSupportedMIMETypesUPP
)osl_getAsciiFunctionSymbol( i_rMod
, "BP_GetSupportedMIMETypes" );
303 noErr
== pBPGetSupp( &aMIMETypesStrangeStruct
, 0 ) &&
304 aMIMETypesStrangeStruct
.typeStrings
)
306 HLock( aMIMETypesStrangeStruct
.typeStrings
);
307 if( aMIMETypesStrangeStruct
.infoStrings
) // it's possible some plugins have infoStrings missing
308 HLock( aMIMETypesStrangeStruct
.infoStrings
);
310 else // Try to get data from the resource fork
312 xRes
= CFBundleOpenBundleResourceMap( i_xBundle
);
315 aMIMETypesStrangeStruct
.typeStrings
= Get1Resource('STR#', 128);
316 if( aMIMETypesStrangeStruct
.typeStrings
)
318 DetachResource( aMIMETypesStrangeStruct
.typeStrings
);
319 HLock( aMIMETypesStrangeStruct
.typeStrings
);
320 aMIMETypesStrangeStruct
.infoStrings
= Get1Resource('STR#', 127);
321 if( aMIMETypesStrangeStruct
.infoStrings
)
323 DetachResource( aMIMETypesStrangeStruct
.infoStrings
);
324 HLock( aMIMETypesStrangeStruct
.infoStrings
);
330 if( aMIMETypesStrangeStruct
.typeStrings
&& aMIMETypesStrangeStruct
.infoStrings
)
332 short nVariantCount
= (**(short**)aMIMETypesStrangeStruct
.typeStrings
) / 2;
333 // Fill in the info struct based on the data in the BPSupportedMIMETypes struct
334 // this is an array of pascal string of unknown (!) encoding
335 // whoever thought of this deserves a fair beating
337 short descriptionIndex
= 2;
338 for( int i
= 0; i
< nVariantCount
; i
++ )
340 rtl::OUString aMimetype
= GetNextPluginStringFromHandle( aMIMETypesStrangeStruct
.typeStrings
, &mimeIndex
);
341 rtl::OUString aExtLine
= GetNextPluginStringFromHandle( aMIMETypesStrangeStruct
.typeStrings
, &mimeIndex
);
342 rtl::OUString aDescription
;
343 if( aMIMETypesStrangeStruct
.infoStrings
)
344 aDescription
= GetNextPluginStringFromHandle( aMIMETypesStrangeStruct
.infoStrings
, &descriptionIndex
);
346 // create extension list string
347 sal_Int32 nExtIndex
= 0;
348 OUStringBuffer aExtension
;
349 while( nExtIndex
!= -1 )
351 OUString aExt
= aExtLine
.getToken( 0, ',', nExtIndex
);
352 if( aExt
.indexOfAsciiL( "*.", 2 ) != 0 )
353 aExtension
.appendAscii( "*." );
354 aExtension
.append( aExt
);
355 if( nExtIndex
!= -1 )
356 aExtension
.append( sal_Unicode(';') );
359 PluginDescription
* pNew
= new PluginDescription
;
360 // set plugin name (path to library)
361 pNew
->PluginName
= i_rBundleURL
;
363 pNew
->Mimetype
= aMimetype
;
364 // set extension line
365 pNew
->Extension
= aExtension
.makeStringAndClear();
367 pNew
->Description
= aDescription
;
368 io_rDescriptions
.push_back( pNew
);
371 #if OSL_DEBUG_LEVEL > 1
373 "Inserting from resource:\n"
376 " Description: %s\n",
377 OUStringToOString( pNew
->Mimetype
, RTL_TEXTENCODING_UTF8
).getStr(),
378 OUStringToOString( pNew
->Extension
, RTL_TEXTENCODING_UTF8
).getStr(),
379 OUStringToOString( pNew
->Description
, RTL_TEXTENCODING_UTF8
).getStr()
387 if( aMIMETypesStrangeStruct
.typeStrings
)
389 HUnlock( aMIMETypesStrangeStruct
.typeStrings
);
390 DisposeHandle( aMIMETypesStrangeStruct
.typeStrings
);
392 if( aMIMETypesStrangeStruct
.infoStrings
)
394 HUnlock( aMIMETypesStrangeStruct
.infoStrings
);
395 DisposeHandle( aMIMETypesStrangeStruct
.infoStrings
);
398 CFBundleCloseBundleResourceMap( i_xBundle
, xRes
);
403 // check some known bad plugins to avoid crashes
404 static bool checkBlackList( CFBundleRef i_xBundle
)
406 rtl::OUString aBundleName
;
407 CFTypeRef bundlename
= CFBundleGetValueForInfoDictionaryKey( i_xBundle
, CFSTR("CFBundleName"));
408 if( bundlename
&& CFGetTypeID(bundlename
) == CFStringGetTypeID() )
409 aBundleName
= getString( static_cast<CFStringRef
>(bundlename
) );
411 rtl::OUString aBundleVersion
;
412 CFTypeRef bundleversion
= CFBundleGetValueForInfoDictionaryKey( i_xBundle
, CFSTR("CFBundleVersion"));
413 if( bundleversion
&& CFGetTypeID(bundleversion
) == CFStringGetTypeID() )
414 aBundleVersion
= getString( static_cast<CFStringRef
>(bundleversion
) );
416 bool bReject
= false;
417 // #i102735# VLC plugin prior to 1.0 tends to crash
418 if( aBundleName
.equalsAscii( "VLC Plug-in" ) )
420 sal_Int32 nIndex
= 0;
421 rtl::OUString
aMajor( aBundleVersion
.getToken( 0, '.', nIndex
) );
422 if( aMajor
.toInt32() < 1 )
427 // #i103674# Garmin Communicator Plugin crashes
428 else if( aBundleName
.equalsAscii( "Garmin Communicator Plugin" ) )
433 #if OSL_DEBUG_LEVEL > 1
435 fprintf( stderr
, "rejecting plugin \"%s\" version %s\n",
436 rtl::OUStringToOString( aBundleName
, RTL_TEXTENCODING_UTF8
).getStr(),
437 rtl::OUStringToOString( aBundleVersion
, RTL_TEXTENCODING_UTF8
).getStr()
444 static int getPluginDescriptions( CFBundleRef i_xBundle
, list
< PluginDescription
* >& io_rDescriptions
)
446 int nDescriptions
= 0;
448 return nDescriptions
;
450 if( checkBlackList( i_xBundle
) )
453 rtl::OUString aPlugURL
;
454 CFURLRef xURL
= CFBundleCopyBundleURL( i_xBundle
);
455 aPlugURL
= getString( xURL
);
458 #if OSL_DEBUG_LEVEL > 1
459 rtl::OUString aPlugName
, aPlugDescription
;
460 CFTypeRef name
= CFBundleGetValueForInfoDictionaryKey( i_xBundle
, CFSTR("WebPluginName"));
461 if( name
&& CFGetTypeID(name
) == CFStringGetTypeID() )
462 aPlugName
= getString( static_cast<CFStringRef
>(name
) );
464 CFTypeRef description
= CFBundleGetValueForInfoDictionaryKey( i_xBundle
, CFSTR("WebPluginDescription"));
465 if( description
&& CFGetTypeID(description
) == CFStringGetTypeID() )
466 aPlugDescription
= getString( static_cast<CFStringRef
>(description
) );
468 fprintf( stderr
, "URL: %s\nname: %s\ndescription: %s\n",
469 rtl::OUStringToOString( aPlugURL
, RTL_TEXTENCODING_UTF8
).getStr(),
470 rtl::OUStringToOString( aPlugName
, RTL_TEXTENCODING_UTF8
).getStr(),
471 rtl::OUStringToOString( aPlugDescription
, RTL_TEXTENCODING_UTF8
).getStr()
476 // get location of plugin library
477 CFURLRef xLibURL
= CFBundleCopyExecutableURL( i_xBundle
);
480 // get the file system path
481 rtl::OUString
aModuleURL( CFURLtoOSLURL( xLibURL
) );
482 CFRelease( xLibURL
);
484 #if OSL_DEBUG_LEVEL > 1
485 fprintf( stderr
, "exec URL = %s\n", rtl::OUStringToOString( aModuleURL
, RTL_TEXTENCODING_UTF8
).getStr() );
488 /* TODO: originally the C++ wrapper for oslModule was used here, but that led to
489 mysterious crashes in the event loop (pointing to heap corruption). Why using
490 the C style oslModule should fix this is completely unknown. It may be that
491 we have just hidden the heap corruption a little more.
493 oslModule aMod
= osl_loadModule( aModuleURL
.pData
, SAL_LOADMODULE_DEFAULT
);
497 // check for at least the init function of a plugin
498 if( ! osl_getAsciiFunctionSymbol( aMod
, "NP_Initialize") &&
499 ! osl_getAsciiFunctionSymbol( aMod
, "NP_GetEntryPoints" ) )
504 // ask the plist of the bundle for mimetypes
505 nDescriptions
= parsePlist( i_xBundle
, aPlugURL
, io_rDescriptions
);
508 osl_unloadModule( aMod
);
509 return nDescriptions
;
512 // resolve the symbol that might get us the mimetypes
513 const char* (*pGetMimeDescription
)() = (const char*(*)())osl_getAsciiFunctionSymbol( aMod
, "_NP_GetMIMEDescription" );
514 if( pGetMimeDescription
)
516 const char* pMime
= pGetMimeDescription();
519 nDescriptions
= parseMimeString( aPlugURL
, io_rDescriptions
, pMime
);
522 osl_unloadModule( aMod
);
523 return nDescriptions
;
528 // and as last resort check the resource of the bundle
529 nDescriptions
= parseMimeResource( i_xBundle
, aMod
, aPlugURL
, io_rDescriptions
);
530 osl_unloadModule( aMod
);
532 return nDescriptions
;
535 // Unix specific implementation
536 static bool CheckPlugin( const rtl::OUString
& rPath
, list
< PluginDescription
* >& rDescriptions
)
538 #if OSL_DEBUG_LEVEL > 1
539 fprintf( stderr
, "Trying path %s ... ", rtl::OUStringToOString( rPath
, RTL_TEXTENCODING_UTF8
).getStr() );
541 CFURLRef xURL
= createURL( rPath
);
543 CFArrayRef xBundles
= CFBundleCreateBundlesFromDirectory( NULL
, xURL
, CFSTR("plugin") );
547 CFIndex nBundles
= CFArrayGetCount( xBundles
);
549 #if OSL_DEBUG_LEVEL > 1
550 fprintf( stderr
, "got %d bundles\n", (int)nBundles
);
553 int nDescriptions
= 0;
554 for( CFIndex i
= 0; i
< nBundles
; i
++ )
556 CFBundleRef xBundle
= (CFBundleRef
)CFArrayGetValueAtIndex( xBundles
, i
);
557 nDescriptions
+= getPluginDescriptions( xBundle
, rDescriptions
);
559 CFRelease( xBundle
);
561 CFRelease( xBundles
);
564 return nDescriptions
> 0;
567 static rtl::OUString
FindFolderURL( FSVolumeRefNum vRefNum
, OSType folderType
)
572 OSErr err
= FSFindFolder( vRefNum
, folderType
, kDontCreateFolder
, &aFSRef
);
575 CFURLRef xURL
= CFURLCreateFromFSRef( NULL
, &aFSRef
);
576 aRet
= getString( xURL
);
583 Sequence
<PluginDescription
> XPluginManager_Impl::impl_getPluginDescriptions() throw()
585 static Sequence
<PluginDescription
> aDescriptions
;
586 static BOOL bHavePlugins
= FALSE
;
589 std::list
<PluginDescription
*> aPlugins
;
591 static const char* pNPXPluginPath
= getenv( "MOZ_PLUGIN_PATH" );
594 std::list
< rtl::OUString
> aPaths
;
597 CFMutableStringRef xMutableString
= CFStringCreateMutable( NULL
, 0 );
598 CFStringAppendCString( xMutableString
, pNPXPluginPath
, kCFStringEncodingUTF8
);
599 CFURLRef xURL
= CFURLCreateWithFileSystemPath( NULL
, xMutableString
, kCFURLPOSIXPathStyle
, true );
600 CFRelease( xMutableString
);
601 aPaths
.push_back( getString( xURL
) );
605 rtl::OUString aPath
= FindFolderURL( kUserDomain
, kInternetPlugInFolderType
);
606 if( aPath
.getLength() )
607 aPaths
.push_back( aPath
);
608 aPath
= FindFolderURL( kLocalDomain
, kInternetPlugInFolderType
);
609 if( aPath
.getLength() )
610 aPaths
.push_back( aPath
);
611 aPath
= FindFolderURL( kOnAppropriateDisk
, kInternetPlugInFolderType
);
612 if( aPath
.getLength() )
613 aPaths
.push_back( aPath
);
616 const Sequence
< ::rtl::OUString
>& rPaths( PluginManager::getAdditionalSearchPaths() );
617 for( sal_Int32 i
= 0; i
< rPaths
.getLength(); i
++ )
619 aPaths
.push_back( getURLFromPath( rPaths
.getConstArray()[i
] ) );
622 for( std::list
< rtl::OUString
>::const_iterator it
= aPaths
.begin(); it
!= aPaths
.end(); ++it
)
624 rtl::OUString
aPath( *it
);
625 #if OSL_DEBUG_LEVEL > 1
626 fprintf( stderr
, "check path %s\n", rtl::OUStringToOString( *it
, RTL_TEXTENCODING_UTF8
).getStr() );
628 CheckPlugin( aPath
, aPlugins
);
632 // create return value
633 aDescriptions
= Sequence
<PluginDescription
>( aPlugins
.size() );
634 #if OSL_DEBUG_LEVEL > 1
635 fprintf( stderr
, "found %d plugins\n", (int)aPlugins
.size() );
637 list
<PluginDescription
*>::iterator iter
;
639 for( iter
= aPlugins
.begin(); iter
!= aPlugins
.end(); ++iter
)
641 aDescriptions
.getArray()[ nPlug
++ ] = **iter
;
647 return aDescriptions
;