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 "qcomlibrary_p.h"
00037
00038 #ifndef QT_NO_COMPONENT
00039 #include <qapplication.h>
00040 #include <qsettings.h>
00041 #include <qfileinfo.h>
00042 #include <qdatetime.h>
00043 #include <qcleanuphandler.h>
00044 #include <errno.h>
00045
00046 #ifdef QT_THREAD_SUPPORT
00047 # include "qmutexpool_p.h"
00048 #endif // QT_THREAD_SUPPORT
00049
00050 #ifndef QT_DEBUG_COMPONENT
00051 # if defined(QT_DEBUG)
00052 # define QT_DEBUG_COMPONENT 1
00053 # endif
00054 #endif
00055
00056
00057 QComLibrary::QComLibrary( const QString &filename )
00058 : QLibrary( filename ), entry( 0 ), libiface( 0 ), qt_version( 0 )
00059 {
00060 }
00061
00062 QComLibrary::~QComLibrary()
00063 {
00064 if ( autoUnload() )
00065 unload();
00066 if ( libiface )
00067 libiface->release();
00068 if ( entry )
00069 entry->release();
00070 }
00071
00072 bool QComLibrary::unload()
00073 {
00074 if ( libiface ) {
00075 libiface->cleanup();
00076 if ( !libiface->canUnload() )
00077 return FALSE;
00078 libiface->release();
00079 libiface = 0;
00080 }
00081 int refs = entry ? entry->release() : 0;
00082 if ( refs )
00083 return FALSE;
00084
00085 entry = 0;
00086
00087 return QLibrary::unload();
00088 }
00089
00090 static bool qt_verify( const QString& library, uint version, uint flags,
00091 const QCString &key, bool warn )
00092 {
00093 uint our_flags = 1;
00094 #if defined(QT_THREAD_SUPPORT)
00095 our_flags |= 2;
00096 #endif
00097
00098 if ( (flags & 1) == 0 ) {
00099 if ( warn )
00100 qWarning( "Conflict in %s:\n"
00101 " Plugin cannot be queried successfully!",
00102 (const char*) QFile::encodeName(library) );
00103 } else if ( ( version > QT_VERSION ) ||
00104 ( ( QT_VERSION & 0xff0000 ) > ( version & 0xff0000 ) ) ) {
00105 if ( warn )
00106 qWarning( "Conflict in %s:\n"
00107 " Plugin uses incompatible Qt library (%d.%d.%d)!",
00108 (const char*) QFile::encodeName(library),
00109 (version&0xff0000) >> 16, (version&0xff00) >> 8, version&0xff );
00110 } else if ( (flags & 2) != (our_flags & 2) ) {
00111 if ( warn )
00112 qWarning( "Conflict in %s:\n"
00113 " Plugin uses %s Qt library!",
00114 (const char*) QFile::encodeName(library),
00115 (flags & 2) ? "multi threaded" : "single threaded" );
00116 } else if ( key != QT_BUILD_KEY ) {
00117 if ( warn )
00118 qWarning( "Conflict in %s:\n"
00119 " Plugin uses incompatible Qt library!\n"
00120 " expected build key \"%s\", got \"%s\".",
00121 (const char*) QFile::encodeName(library),
00122 QT_BUILD_KEY,
00123 key.isEmpty() ? "<null>" : (const char *) key );
00124 } else {
00125 return TRUE;
00126 }
00127 return FALSE;
00128 }
00129
00130 struct qt_token_info
00131 {
00132 qt_token_info( const char *f, const ulong fc )
00133 : fields( f ), field_count( fc ), results( fc ), lengths( fc )
00134 {
00135 results.fill( 0 );
00136 lengths.fill( 0 );
00137 }
00138
00139 const char *fields;
00140 const ulong field_count;
00141
00142 QMemArray<const char *> results;
00143 QMemArray<ulong> lengths;
00144 };
00145
00146
00147
00148
00149
00150
00151
00152 static int qt_tokenize( const char *s, ulong s_len, ulong *advance,
00153 const qt_token_info &token_info )
00154 {
00155 ulong pos = 0, field = 0, fieldlen = 0;
00156 char current;
00157 int ret = -1;
00158 *advance = 0;
00159 for (;;) {
00160 current = s[ pos ];
00161
00162
00163 ++pos;
00164 ++fieldlen;
00165 ++*advance;
00166
00167 if ( ! current || pos == s_len + 1 ) {
00168
00169 token_info.results[ (int)field ] = s;
00170 token_info.lengths[ (int)field ] = fieldlen - 1;
00171
00172
00173 ret = 0;
00174 break;
00175 }
00176
00177 if ( current == token_info.fields[ field ] ) {
00178
00179 token_info.results[ (int)field ] = s;
00180 token_info.lengths[ (int)field ] = fieldlen - 1;
00181
00182
00183 fieldlen = 0;
00184 ++field;
00185 if ( field == token_info.field_count - 1 ) {
00186
00187 ret = 1;
00188 }
00189 if ( field == token_info.field_count ) {
00190
00191 break;
00192 }
00193
00194
00195 s = s + pos;
00196 s_len -= pos;
00197 pos = 0;
00198 }
00199 }
00200
00201 return ret;
00202 }
00203
00204
00205
00206
00207 static bool qt_parse_pattern( const char *s, uint *version, uint *flags,
00208 QCString *key )
00209 {
00210 bool ret = TRUE;
00211
00212 qt_token_info pinfo("=\n", 2);
00213 int parse;
00214 ulong at = 0, advance, parselen = qstrlen( s );
00215 do {
00216 parse = qt_tokenize( s + at, parselen, &advance, pinfo );
00217 if ( parse == -1 ) {
00218 ret = FALSE;
00219 break;
00220 }
00221
00222 at += advance;
00223 parselen -= advance;
00224
00225 if ( qstrncmp( "version", pinfo.results[ 0 ], pinfo.lengths[ 0 ] ) == 0 ) {
00226
00227 qt_token_info pinfo2("..-", 3);
00228 if ( qt_tokenize( pinfo.results[ 1 ], pinfo.lengths[ 1 ],
00229 &advance, pinfo2 ) != -1 ) {
00230 QCString m( pinfo2.results[ 0 ], pinfo2.lengths[ 0 ] + 1 );
00231 QCString n( pinfo2.results[ 1 ], pinfo2.lengths[ 1 ] + 1 );
00232 QCString p( pinfo2.results[ 2 ], pinfo2.lengths[ 2 ] + 1 );
00233 *version = (m.toUInt() << 16) | (n.toUInt() << 8) | p.toUInt();
00234 } else {
00235 ret = FALSE;
00236 break;
00237 }
00238 } else if ( qstrncmp( "flags", pinfo.results[ 0 ], pinfo.lengths[ 0 ] ) == 0 ) {
00239
00240 char ch;
00241 *flags = 0;
00242 ulong p = 0, c = 0, bit = 0;
00243 while ( p < pinfo.lengths[ 1 ] ) {
00244 ch = pinfo.results[ 1 ][ p ];
00245 bit = pinfo.lengths[ 1 ] - p - 1;
00246 c = 1 << bit;
00247 if ( ch == '1' ) {
00248 *flags |= c;
00249 } else if ( ch != '0' ) {
00250 ret = FALSE;
00251 break;
00252 }
00253 ++p;
00254 }
00255 } else if ( qstrncmp( "buildkey", pinfo.results[ 0 ],
00256 pinfo.lengths[ 0 ] ) == 0 ){
00257
00258 *key = QCString( pinfo.results[ 1 ], pinfo.lengths[ 1 ] + 1 );
00259 }
00260 } while ( parse == 1 && parselen > 0 );
00261
00262 return ret;
00263 }
00264
00265 #if defined(Q_OS_UNIX)
00266
00267 #if defined(Q_OS_FREEBSD) || defined(Q_OS_LINUX)
00268 # define USE_MMAP
00269 # include <sys/types.h>
00270 # include <sys/mman.h>
00271 #endif // Q_OS_FREEBSD || Q_OS_LINUX
00272
00273 static long qt_find_pattern( const char *s, ulong s_len,
00274 const char *pattern, ulong p_len )
00275 {
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290 if ( ! s || ! pattern || p_len > s_len ) return -1;
00291 ulong i, hs = 0, hp = 0, delta = s_len - p_len;
00292
00293 for (i = 0; i < p_len; ++i ) {
00294 hs += s[delta + i];
00295 hp += pattern[i];
00296 }
00297 i = delta;
00298 for (;;) {
00299 if ( hs == hp && qstrncmp( s + i, pattern, p_len ) == 0 )
00300 return i;
00301 if ( i == 0 )
00302 break;
00303 --i;
00304 hs -= s[i + p_len];
00305 hs += s[i];
00306 }
00307
00308 return -1;
00309 }
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321 static bool qt_unix_query( const QString &library, uint *version, uint *flags,
00322 QCString *key )
00323 {
00324 QFile file( library );
00325 if (! file.open( IO_ReadOnly ) ) {
00326 qWarning( "%s: %s", (const char*) QFile::encodeName(library),
00327 strerror( errno ) );
00328 return FALSE;
00329 }
00330
00331 QByteArray data;
00332 char *filedata = 0;
00333 ulong fdlen = 0;
00334
00335 #ifdef USE_MMAP
00336 char *mapaddr = 0;
00337 size_t maplen = file.size();
00338 mapaddr = (char *) mmap( mapaddr, maplen, PROT_READ, MAP_PRIVATE, file.handle(), 0 );
00339 if ( mapaddr != MAP_FAILED ) {
00340
00341 filedata = mapaddr;
00342 fdlen = maplen;
00343 } else {
00344
00345 qWarning( "mmap: %s", strerror( errno ) );
00346 #endif // USE_MMAP
00347
00348 data = file.readAll();
00349 filedata = data.data();
00350 fdlen = data.size();
00351 #ifdef USE_MMAP
00352 }
00353 #endif // USE_MMAP
00354
00355
00356 const char *pattern = "pattern=QT_UCM_VERIFICATION_DATA";
00357 const ulong plen = qstrlen( pattern );
00358 long pos = qt_find_pattern( filedata, fdlen, pattern, plen );
00359
00360 bool ret = FALSE;
00361 if ( pos >= 0 ) {
00362 ret = qt_parse_pattern( filedata + pos, version, flags, key );
00363 }
00364
00365 #ifdef USE_MMAP
00366 if ( mapaddr != MAP_FAILED && munmap(mapaddr, maplen) != 0 ) {
00367 qWarning( "munmap: %s", strerror( errno ) );
00368 }
00369 #endif // USE_MMAP
00370
00371 file.close();
00372 return ret;
00373 }
00374
00375 #endif // Q_OS_UNIX
00376
00377
00378 static QSettings *cache = 0;
00379 static QSingleCleanupHandler<QSettings> cleanup_cache;
00380
00381 void QComLibrary::createInstanceInternal()
00382 {
00383 if ( library().isEmpty() )
00384 return;
00385
00386 QFileInfo fileinfo( library() );
00387 QString lastModified = fileinfo.lastModified().toString();
00388 QString regkey = QString("/Qt Plugins %1.%2/%3")
00389 .arg( ( QT_VERSION & 0xff0000 ) >> 16 )
00390 .arg( ( QT_VERSION & 0xff00 ) >> 8 )
00391 .arg( library() );
00392 QStringList reg;
00393 uint flags = 0;
00394 QCString key;
00395 bool query_done = FALSE;
00396 bool warn_mismatch = TRUE;
00397
00398 #ifdef QT_THREAD_SUPPORT
00399 QMutexLocker locker( qt_global_mutexpool ?
00400 qt_global_mutexpool->get( &cache ) : 0 );
00401 #endif // QT_THREAD_SUPPORT
00402
00403 if ( ! cache ) {
00404 cache = new QSettings;
00405 cache->insertSearchPath( QSettings::Windows, "/Trolltech" );
00406 cleanup_cache.set( &cache );
00407 }
00408
00409 reg = cache->readListEntry( regkey );
00410 if ( reg.count() == 4 ) {
00411
00412 if ( lastModified == reg[3] ) {
00413 qt_version = reg[0].toUInt(0, 16);
00414 flags = reg[1].toUInt(0, 16);
00415 key = reg[2].latin1();
00416
00417 query_done = TRUE;
00418 warn_mismatch = FALSE;
00419 }
00420 }
00421
00422 #if defined(Q_OS_UNIX)
00423 if ( ! query_done ) {
00424
00425 if ( qt_unix_query( library(), &qt_version, &flags, &key ) ) {
00426
00427 query_done = TRUE;
00428 }
00429 }
00430 #else // !Q_OS_UNIX
00431 if ( ! query_done ) {
00432
00433 if ( !isLoaded() ) {
00434 Q_ASSERT( entry == 0 );
00435 if ( !load() )
00436 return;
00437 }
00438
00439 # ifdef Q_CC_BOR
00440 typedef const char * __stdcall (*UCMQueryVerificationDataProc)();
00441 # else
00442 typedef const char * (*UCMQueryVerificationDataProc)();
00443 # endif
00444 UCMQueryVerificationDataProc ucmQueryVerificationdataProc;
00445 ucmQueryVerificationdataProc =
00446 (UCMQueryVerificationDataProc) resolve( "qt_ucm_query_verification_data" );
00447
00448 if ( !ucmQueryVerificationdataProc ||
00449 !qt_parse_pattern( ucmQueryVerificationdataProc(),
00450 &qt_version, &flags, &key ) ) {
00451 qt_version = flags = 0;
00452 key = "unknown";
00453 } else {
00454 query_done = TRUE;
00455 }
00456 }
00457 #endif // Q_OS_UNIX
00458
00459 QStringList queried;
00460 queried << QString::number( qt_version,16 )
00461 << QString::number( flags, 16 )
00462 << key
00463 << lastModified;
00464
00465 if ( queried != reg ) {
00466 cache->writeEntry( regkey, queried );
00467
00468 delete cache;
00469 cache = 0;
00470 }
00471
00472 if ( ! query_done ) {
00473 if ( warn_mismatch ) {
00474 qWarning( "Conflict in %s:\n Plugin cannot be queried successfully!",
00475 (const char*) QFile::encodeName( library() ) );
00476 }
00477 unload();
00478 return;
00479 }
00480
00481 if ( ! qt_verify( library(), qt_version, flags, key, warn_mismatch ) ) {
00482 unload();
00483 return;
00484 } else if ( !isLoaded() ) {
00485 Q_ASSERT( entry == 0 );
00486 if ( !load() )
00487 return;
00488 }
00489
00490 #ifdef Q_CC_BOR
00491 typedef QUnknownInterface* __stdcall (*UCMInstanceProc)();
00492 #else
00493 typedef QUnknownInterface* (*UCMInstanceProc)();
00494 #endif
00495 UCMInstanceProc ucmInstanceProc;
00496 ucmInstanceProc = (UCMInstanceProc) resolve( "ucm_instantiate" );
00497 #if defined(QT_DEBUG_COMPONENT)
00498 if ( !ucmInstanceProc )
00499 qWarning( "%s: Not a UCOM library.", (const char*) QFile::encodeName(library()) );
00500 #endif
00501 entry = ucmInstanceProc ? ucmInstanceProc() : 0;
00502
00503 if ( entry ) {
00504 if ( entry->queryInterface( IID_QLibrary, (QUnknownInterface**)&libiface ) == QS_OK ) {
00505 if ( libiface && !libiface->init() ) {
00506 libiface->release();
00507 libiface = 0;
00508 unload();
00509 return;
00510 }
00511 }
00512 } else {
00513 #if defined(QT_DEBUG_COMPONENT)
00514 qWarning( "%s: No exported component provided.", (const char*) QFile::encodeName(library()) );
00515 #endif
00516 unload();
00517 }
00518 }
00519
00520 QRESULT QComLibrary::queryInterface( const QUuid& request, QUnknownInterface** iface )
00521 {
00522 if ( !entry )
00523 createInstanceInternal();
00524 return entry ? entry->queryInterface( request, iface ) : QE_NOCOMPONENT;
00525 }
00526
00527 uint QComLibrary::qtVersion()
00528 {
00529 if ( !entry )
00530 createInstanceInternal();
00531 return entry ? qt_version : 0;
00532 }
00533
00534
00535 #endif // QT_NO_COMPONENT