00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036 #include "qgpluginmanager_p.h"
00037 #ifndef QT_NO_COMPONENT
00038 #include "qcomlibrary_p.h"
00039 #include "qmap.h"
00040 #include "qdir.h"
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078 static const char indexOf[256] = {
00079 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00080 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00081
00082 0, 2, 6, 7, 10, 12, 15, 19, 2, 6, 7, 10, 12, 15, 19, 0,
00083
00084 1, 3, 4, 5, 8, 9, 11, 13, 14, 16, 2, 6, 7, 10, 12, 15,
00085
00086 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 6, 10, 11, 12, 13, 14,
00087
00088 15, 12, 16, 17, 18, 19, 2, 10, 15, 7, 19, 2, 6, 7, 10, 0,
00089
00090 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 6, 10, 11, 12, 13, 14,
00091
00092 15, 12, 16, 17, 18, 19, 2, 10, 15, 7, 19, 2, 6, 7, 10, 0,
00093
00094 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00095 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00096 0, 2, 6, 7, 10, 12, 15, 19, 2, 6, 7, 10, 12, 15, 19, 0,
00097 1, 3, 4, 5, 8, 9, 11, 13, 14, 16, 2, 6, 7, 10, 12, 15,
00098 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 6, 10, 11, 12, 13, 14,
00099 15, 12, 16, 17, 18, 19, 2, 10, 15, 7, 19, 2, 6, 7, 10, 0,
00100 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 6, 10, 11, 12, 13, 14,
00101 15, 12, 16, 17, 18, 19, 2, 10, 15, 7, 19, 2, 6, 7, 10, 0
00102 };
00103
00104
00105
00106
00107
00108 static const char bitCount[256] = {
00109 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
00110 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
00111 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
00112 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
00113 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
00114 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
00115 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
00116 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
00117 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
00118 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
00119 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
00120 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
00121 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
00122 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
00123 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
00124 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8
00125 };
00126
00127 class QCoMatrix
00128 {
00129 public:
00130
00131
00132
00133
00134
00135 union {
00136 Q_UINT8 b[52];
00137 Q_UINT32 w[13];
00138 };
00139
00140 QCoMatrix() { memset( b, 0, 52 ); }
00141 QCoMatrix( const char *text ) {
00142 char c = '\0', d;
00143 memset( b, 0, 52 );
00144 while ( (d = *text) != '\0' ) {
00145 setCoocc( c, d );
00146 if ( (c = *++text) != '\0' ) {
00147 setCoocc( d, c );
00148 text++;
00149 }
00150 }
00151 }
00152
00153 void setCoocc( char c, char d ) {
00154 int k = indexOf[(uchar) c] + 20 * indexOf[(uchar) d];
00155 b[k >> 3] |= k & 0x7;
00156 }
00157
00158 int worth() const {
00159 int result = 0;
00160 for ( int i = 0; i < 50; i++ )
00161 result += bitCount[b[i]];
00162 return result;
00163 }
00164
00165 static QCoMatrix reunion( const QCoMatrix& m, const QCoMatrix& n )
00166 {
00167 QCoMatrix p;
00168 for ( int i = 0; i < 13; i++ )
00169 p.w[i] = m.w[i] | n.w[i];
00170 return p;
00171 }
00172 static QCoMatrix intersection( const QCoMatrix& m, const QCoMatrix& n )
00173 {
00174 QCoMatrix p;
00175 for ( int i = 0; i < 13; i++ )
00176 p.w[i] = m.w[i] & n.w[i];
00177 return p;
00178 }
00179 };
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196 static int similarity( const QString& s1, const QString& s2 )
00197 {
00198 QCoMatrix m1( s1 );
00199 QCoMatrix m2( s2 );
00200 return ( 15 * (QCoMatrix::intersection(m1, m2).worth() + 1) ) /
00201 ( QCoMatrix::reunion(m1, m2).worth() + 1 );
00202 }
00203
00287 #include <qptrlist.h>
00288
00289 QGPluginManager::QGPluginManager( const QUuid& id, const QStringList& paths, const QString &suffix, bool cs )
00290 : interfaceId( id ), plugDict( 17, cs ), casesens( cs ), autounload( TRUE )
00291 {
00292
00293 libDict.setAutoDelete( TRUE );
00294 for ( QStringList::ConstIterator it = paths.begin(); it != paths.end(); ++it ) {
00295 QString path = *it;
00296 addLibraryPath( path + suffix );
00297 }
00298 }
00299
00300 QGPluginManager::~QGPluginManager()
00301 {
00302 if ( !autounload ) {
00303 QDictIterator<QLibrary> it( libDict );
00304 while ( it.current() ) {
00305 QLibrary *lib = it.current();
00306 ++it;
00307 lib->setAutoUnload( FALSE );
00308 }
00309 }
00310 }
00311
00312 void QGPluginManager::addLibraryPath( const QString& path )
00313 {
00314 if ( !enabled() || !QDir( path ).exists( ".", TRUE ) )
00315 return;
00316
00317 #if defined(Q_OS_WIN32)
00318 QString filter = "dll";
00319 #elif defined(Q_OS_MACX)
00320 QString filter = "dylib";
00321 #elif defined(Q_OS_UNIX)
00322 QString filter = "so";
00323 #endif
00324
00325 QStringList plugins = QDir(path).entryList( "*." + filter );
00326 for ( QStringList::Iterator p = plugins.begin(); p != plugins.end(); ++p ) {
00327 QString lib = QDir::cleanDirPath( path + "/" + *p );
00328 if ( libList.contains( lib ) )
00329 continue;
00330 libList.append( lib );
00331 }
00332 }
00333
00334 const QLibrary* QGPluginManager::library( const QString& feature ) const
00335 {
00336 if ( !enabled() || feature.isEmpty() )
00337 return 0;
00338
00339
00340 QLibrary *library = 0;
00341 if ( ( library = plugDict[feature] ) )
00342 return library;
00343
00344
00345 QMap<int, QStringList> map;
00346 QStringList::ConstIterator it = libList.begin();
00347 int best = 0;
00348 int worst = 15;
00349 while ( it != libList.end() ) {
00350 if ( (*it).isEmpty() || libDict[*it] ) {
00351 ++it;
00352 continue;
00353 }
00354 QString basename = QFileInfo(*it).baseName();
00355 int s = similarity( feature, basename );
00356 if ( s < worst )
00357 worst = s;
00358 if ( s > best )
00359 best = s;
00360 map[s].append( basename + QChar(0xfffd) + *it );
00361 ++it;
00362 }
00363
00364 if ( map.isEmpty() )
00365 return 0;
00366
00367
00368 QGPluginManager *that = (QGPluginManager*)this;
00369 for ( int s = best; s >= worst; --s ) {
00370 QStringList group = map[s];
00371 group.sort();
00372 QStringList::ConstIterator git = group.begin();
00373 while ( git != group.end() ) {
00374 QString lib = (*git).mid( (*git).find( QChar(0xfffd) ) + 1 );
00375 QString basename = (*git).left( (*git).find( QChar(0xfffd) ) );
00376 ++git;
00377
00378 QStringList sameBasename;
00379 while( git != group.end() &&
00380 basename == (*git).left( (*git).find( QChar(0xfffd) ) ) ) {
00381 sameBasename << (*git).mid( (*git).find( QChar(0xfffd) ) + 1 );
00382 ++git;
00383 }
00384
00385 if ( sameBasename.isEmpty() ) {
00386 that->addLibrary( new QComLibrary( lib ) );
00387 } else {
00388 QPtrList<QComLibrary> same;
00389 same.setAutoDelete( TRUE );
00390 for ( QStringList::ConstIterator bit = sameBasename.begin();
00391 bit != sameBasename.end(); ++bit )
00392 same.append( new QComLibrary( *bit ) );
00393 QComLibrary* bestMatch = 0;
00394 for ( QComLibrary* candidate = same.first(); candidate; candidate = same.next() )
00395 if ( candidate->qtVersion() && candidate->qtVersion() <= QT_VERSION
00396 && ( !bestMatch || candidate->qtVersion() > bestMatch->qtVersion() ) )
00397 bestMatch = candidate;
00398 if ( bestMatch ) {
00399 same.find( bestMatch );
00400 that->addLibrary( same.take() );
00401 }
00402 }
00403
00404 if ( ( library = that->plugDict[feature] ) )
00405 return library;
00406 }
00407 }
00408 return 0;
00409 }
00410
00411 QStringList QGPluginManager::featureList() const
00412 {
00413 QStringList features;
00414
00415 if ( !enabled() )
00416 return features;
00417
00418 QGPluginManager *that = (QGPluginManager*)this;
00419 QStringList theLibs = libList;
00420 QStringList phase2Libs;
00421 QStringList phase2Deny;
00422
00423
00424
00425
00426
00427 QStringList::Iterator it;
00428 for ( it = theLibs.begin(); it != theLibs.end(); ++it ) {
00429 if ( (*it).isEmpty() || libDict[*it] )
00430 continue;
00431 QComLibrary* library = new QComLibrary( *it );
00432 if ( library->qtVersion() == QT_VERSION ) {
00433 that->addLibrary( library );
00434 phase2Deny << QFileInfo( *it ).baseName();
00435 } else {
00436 delete library;
00437 phase2Libs << *it;
00438 }
00439 }
00440 for ( it = phase2Libs.begin(); it != phase2Libs.end(); ++it )
00441 if ( !phase2Deny.contains( QFileInfo( *it ).baseName() ) )
00442 that->addLibrary( new QComLibrary( *it ) );
00443
00444 for ( QDictIterator<QLibrary> pit( plugDict ); pit.current(); ++pit )
00445 features << pit.currentKey();
00446
00447 return features;
00448 }
00449
00450 bool QGPluginManager::addLibrary( QLibrary* lib )
00451 {
00452 if ( !enabled() || !lib )
00453 return FALSE;
00454
00455 QComLibrary* plugin = (QComLibrary*)lib;
00456 bool useful = FALSE;
00457
00458 QUnknownInterface* iFace = 0;
00459 plugin->queryInterface( interfaceId, &iFace );
00460 if ( iFace ) {
00461 QFeatureListInterface *fliFace = 0;
00462 QComponentInformationInterface *cpiFace = 0;
00463 iFace->queryInterface( IID_QFeatureList, (QUnknownInterface**)&fliFace );
00464 if ( !fliFace )
00465 plugin->queryInterface( IID_QFeatureList, (QUnknownInterface**)&fliFace );
00466 if ( !fliFace ) {
00467 iFace->queryInterface( IID_QComponentInformation, (QUnknownInterface**)&cpiFace );
00468 if ( !cpiFace )
00469 plugin->queryInterface( IID_QComponentInformation, (QUnknownInterface**)&cpiFace );
00470 }
00471 QStringList fl;
00472 if ( fliFace )
00473
00474 fl = fliFace->featureList();
00475 else if ( cpiFace )
00476 fl << cpiFace->name();
00477
00478 for ( QStringList::Iterator f = fl.begin(); f != fl.end(); ++f ) {
00479 QLibrary *old = plugDict[*f];
00480 if ( !old ) {
00481 useful = TRUE;
00482 plugDict.replace( *f, plugin );
00483 } else {
00484
00485 QComLibrary* first = (QComLibrary*)old;
00486 QComLibrary* second = (QComLibrary*)plugin;
00487 bool takeFirst = TRUE;
00488 if ( first->qtVersion() != QT_VERSION ) {
00489 if ( second->qtVersion() == QT_VERSION )
00490 takeFirst = FALSE;
00491 else if ( second->qtVersion() < QT_VERSION &&
00492 first->qtVersion() > QT_VERSION )
00493 takeFirst = FALSE;
00494 }
00495 if ( !takeFirst ) {
00496 useful = TRUE;
00497 plugDict.replace( *f, plugin );
00498 qWarning("%s: Discarding feature %s in %s!",
00499 (const char*) QFile::encodeName( plugin->library()),
00500 (*f).latin1(),
00501 (const char*) QFile::encodeName( old->library() ) );
00502 } else {
00503 qWarning("%s: Feature %s already defined in %s!",
00504 (const char*) QFile::encodeName( old->library() ),
00505 (*f).latin1(),
00506 (const char*) QFile::encodeName( plugin->library() ) );
00507 }
00508 }
00509 }
00510 if ( fliFace )
00511 fliFace->release();
00512 if ( cpiFace )
00513 cpiFace->release();
00514 iFace->release();
00515 }
00516
00517 if ( useful ) {
00518 libDict.replace( plugin->library(), plugin );
00519 if ( !libList.contains( plugin->library() ) )
00520 libList.append( plugin->library() );
00521 return TRUE;
00522 }
00523 delete plugin;
00524 return FALSE;
00525 }
00526
00527
00528 bool QGPluginManager::enabled() const
00529 {
00530 #ifdef QT_SHARED
00531 return TRUE;
00532 #else
00533 return FALSE;
00534 #endif
00535 }
00536
00537 QRESULT QGPluginManager::queryUnknownInterface(const QString& feature, QUnknownInterface** iface) const
00538 {
00539 QComLibrary* plugin = 0;
00540 plugin = (QComLibrary*)library( feature );
00541 return plugin ? plugin->queryInterface( interfaceId, (QUnknownInterface**)iface ) : QE_NOINTERFACE;
00542 }
00543
00544 #endif //QT_NO_COMPONENT