src/multimedia/qmediapluginloader.cpp
changeset 5 603d3f8b6302
parent 0 876b1a06bc25
--- a/src/multimedia/qmediapluginloader.cpp	Fri Sep 17 08:34:34 2010 +0300
+++ b/src/multimedia/qmediapluginloader.cpp	Mon Oct 04 01:37:06 2010 +0300
@@ -46,17 +46,70 @@
 #include <QtCore/qdebug.h>
 
 #include "qmediaserviceproviderplugin.h"
-#include "qmobilitypluginsearch.h"
+
+#if defined(Q_OS_SYMBIAN)
+# include <f32file.h>
+#endif
+
+#if defined(Q_OS_MAC)
+# include <CoreFoundation/CoreFoundation.h>
+#endif
 
 QT_BEGIN_NAMESPACE
 
 typedef QMap<QString,QObjectList> ObjectListMap;
 Q_GLOBAL_STATIC(ObjectListMap, staticMediaPlugins);
 
+
+#if defined(Q_OS_SYMBIAN)
+// XXX: Copied over from Mobility, hopefully to be removed at some point
+class DirChecker
+{
+public:
+    DirChecker();
+    ~DirChecker();
+    bool checkDir(const QDir& dir);
+
+private:
+    RFs rfs;
+};
+
+DirChecker::DirChecker()
+{
+    qt_symbian_throwIfError(rfs.Connect());
+}
+
+bool DirChecker::checkDir(const QDir& dir)
+{
+    bool pathFound = false;
+    // In Symbian, going cdUp() in a c:/private/<uid3>/ will result in *platsec* error at fileserver (requires AllFiles capability)
+    // Also, trying to cd() to a nonexistent directory causes *platsec* error. This does not cause functional harm, but should
+    // nevertheless be changed to use native Symbian methods to avoid unnecessary platsec warnings (as per qpluginloader.cpp).
+    // Use native Symbian code to check for directory existence, because checking
+    // for files from under non-existent protected dir like E:/private/<uid> using
+    // QDir::exists causes platform security violations on most apps.
+    QString nativePath = QDir::toNativeSeparators(dir.absolutePath());
+    TPtrC ptr = TPtrC16(static_cast<const TUint16*>(nativePath.utf16()), nativePath.length());
+    TUint attributes;
+    TInt err = rfs.Att(ptr, attributes);
+    if (err == KErrNone) {
+        // yes, the directory exists.
+        pathFound = true;
+    }
+    return pathFound;
+}
+
+DirChecker::~DirChecker()
+{
+    rfs.Close();
+}
+#endif
+
+
 QMediaPluginLoader::QMediaPluginLoader(const char *iid, const QString &location, Qt::CaseSensitivity):
     m_iid(iid)
 {
-    m_location = location + "/";
+    m_location = QString::fromLatin1("/%1").arg(location);
     load();
 }
 
@@ -78,7 +131,83 @@
 //to be used for testing purposes only
 void QMediaPluginLoader::setStaticPlugins(const QString &location, const QObjectList& objects)
 {
-    staticMediaPlugins()->insert(location+"/", objects);
+    staticMediaPlugins()->insert(QString::fromLatin1("/%1").arg(location), objects);
+}
+
+QStringList QMediaPluginLoader::availablePlugins() const
+{
+    QStringList paths;
+    QStringList plugins;
+
+#if defined(Q_OS_SYMBIAN)
+    DirChecker dirChecker;
+#endif
+
+#if defined(Q_OS_MAC)
+    QString imageSuffix(qgetenv("DYLD_IMAGE_SUFFIX"));
+
+    // Bundle plugin directory
+    CFBundleRef mainBundle = CFBundleGetMainBundle();
+    if (mainBundle != 0) {
+        CFURLRef baseUrl = CFBundleCopyBundleURL(mainBundle);
+        CFURLRef pluginUrlPart = CFBundleCopyBuiltInPlugInsURL(mainBundle);
+        CFStringRef pluginPathPart = CFURLCopyFileSystemPath(pluginUrlPart, kCFURLPOSIXPathStyle);
+        CFURLRef pluginUrl = CFURLCreateCopyAppendingPathComponent(0, baseUrl, pluginPathPart, true);
+        CFStringRef pluginPath = CFURLCopyFileSystemPath(pluginUrl, kCFURLPOSIXPathStyle);
+
+        CFIndex length = CFStringGetLength(pluginPath);
+        UniChar buffer[length];
+        CFStringGetCharacters(pluginPath, CFRangeMake(0, length), buffer);
+
+        paths << QString(reinterpret_cast<const QChar *>(buffer), length);
+
+        CFRelease(pluginPath);
+        CFRelease(pluginUrl);
+        CFRelease(pluginPathPart);
+        CFRelease(pluginUrlPart);
+        CFRelease(baseUrl);
+    }
+#endif
+
+#ifdef QTM_PLUGIN_PATH
+    // Mobility's plugin directory
+    paths << QLatin1String(QTM_PLUGIN_PATH);
+#endif
+
+    // Qt paths
+    paths << QCoreApplication::libraryPaths();
+
+    foreach (const QString &path, paths) {
+        QDir typeDir(path + m_location);
+#if defined(Q_OS_SYMBIAN)
+        if (dirChecker.checkDir(typeDir))
+#endif
+        {
+            foreach (const QString &file, typeDir.entryList(QDir::Files)) {
+#if defined(Q_OS_MAC)
+                if (!imageSuffix.isEmpty()) {   // Only add appropriate images
+                    if (file.lastIndexOf(imageSuffix, -6) == -1)
+                        continue;
+                } else {  // Ignore any images with common suffixes
+                    if (file.endsWith(QLatin1String("_debug.dylib")) ||
+                        file.endsWith(QLatin1String("_profile.dylib")))
+                        continue;
+                }
+#elif defined(Q_OS_UNIX)
+                // Ignore separate debug files
+                if (file.endsWith(QLatin1String(".debug")))
+                    continue;
+#elif defined(Q_OS_WIN)
+                // Ignore non-dlls
+                if (!file.endsWith(QLatin1String(".dll"), Qt::CaseInsensitive))
+                    continue;
+#endif
+                plugins << typeDir.absoluteFilePath(file);
+            }
+        }
+    }
+
+    return  plugins;
 }
 
 void QMediaPluginLoader::load()
@@ -97,25 +226,27 @@
             }
         }
     } else {
-        QStringList plugins = QTM_PREPEND_NAMESPACE(mobilityPlugins)(m_location);
-        for (int i=0; i < plugins.count(); i++) {
-            QPluginLoader   loader(plugins.at(i));
+        foreach (const QString &plugin, availablePlugins()) {
+            QPluginLoader   loader(plugin);
+
             QObject *o = loader.instance();
             if (o != 0 && o->qt_metacast(m_iid) != 0) {
                 QFactoryInterface* p = qobject_cast<QFactoryInterface*>(o);
                 if (p != 0) {
-                    foreach (QString const &key, p->keys())
+                    foreach (const QString &key, p->keys())
                         m_instances.insertMulti(key, o);
                 }
 
                 continue;
             } else {
-                qWarning() << "QMediaPluginLoader: Failed to load plugin: " << plugins.at(i) << loader.errorString();
+                qWarning() << "QMediaPluginLoader: Failed to load plugin: " << plugin << loader.errorString();
             }
+
             delete o;
             loader.unload();
         }
     }
 }
+
 QT_END_NAMESPACE