From 72d60ea08c14037250459a5424ffee7a36b909b1 Mon Sep 17 00:00:00 2001 From: Samuel Gaist Date: Wed, 18 Sep 2013 22:36:51 +0200 Subject: [PATCH] Refactor OS X bundle detection for QFileInfo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CFBundleGetPackageInfoInDirectory originally used tests for the presence of information that are not mandatory in a bundle. The new implementation uses known bundle extensions as well as Launch Services to try to find if the bundle is known to the system. Last thing it checks whether the package bit is set. Task-number: QTBUG-31884 Change-Id: Ib58996c6ac65194c21238f5f86f78d797e310608 Reviewed-by: Thiago Macieira Reviewed-by: Tor Arne Vestbø --- src/corelib/io/qfilesystemengine_unix.cpp | 83 ++++++++++++++++++++--- 1 file changed, 72 insertions(+), 11 deletions(-) diff --git a/src/corelib/io/qfilesystemengine_unix.cpp b/src/corelib/io/qfilesystemengine_unix.cpp index 46d8101e206..e6b4e5f754f 100644 --- a/src/corelib/io/qfilesystemengine_unix.cpp +++ b/src/corelib/io/qfilesystemengine_unix.cpp @@ -1,5 +1,6 @@ /**************************************************************************** ** +** Copyright (C) 2013 Samuel Gaist > ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** @@ -55,6 +56,7 @@ #if defined(Q_OS_MAC) # include +# include #endif QT_BEGIN_NAMESPACE @@ -78,6 +80,74 @@ static inline bool _q_isMacHidden(const char *nativePath) FileInfo * const fileInfo = reinterpret_cast(&catInfo.finderInfo); return (fileInfo->finderFlags & kIsInvisible); } + +static bool isPackage(const QFileSystemMetaData &data, const QFileSystemEntry &entry) +{ + if (!data.isDirectory()) + return false; + + QFileInfo info(entry.filePath()); + QString suffix = info.suffix(); + + // First step: is the extenstion known ? + if (suffix == QLatin1String("app") + || suffix == QLatin1String("debug") + || suffix == QLatin1String("profile") + || suffix == QLatin1String("bundle") + || suffix == QLatin1String("pkg")) { + return true; + } + + // Second step: check if an application knows the package type + const QByteArray &native = entry.nativeFilePath(); + const char *nativeFilePath = native.constData(); + int nativeFilePathLength = native.size(); + + QCFType path = CFStringCreateWithBytes(0, + reinterpret_cast(nativeFilePath), + nativeFilePathLength, + kCFStringEncodingUTF8, + false); + + QCFType url = CFURLCreateWithFileSystemPath(0, path, kCFURLPOSIXPathStyle, true); + + UInt32 type, creator; + // Well created packages have the PkgInfo file + if (CFBundleGetPackageInfoInDirectory(url, &type, &creator)) + return true; + + // Find if an application other than Finder claims to know how to handle the package + if (suffix.length() > 0) { + QCFType application; + LSGetApplicationForURL(url, + kLSRolesEditor|kLSRolesViewer|kLSRolesViewer, + NULL, + &application); + + if (application) { + CFStringRef path = CFURLGetString(application); + QString applicationPath = QCFString::toQString(path); + if (applicationPath != QLatin1String("file://localhost/System/Library/CoreServices/Finder.app/")) + return true; + } + } + + // Third step: check if the directory has the package bit set + FSRef packageRef; + FSPathMakeRef((UInt8 *)nativeFilePath, &packageRef, NULL); + + FSCatalogInfo catalogInfo; + FSGetCatalogInfo(&packageRef, + kFSCatInfoFinderInfo, + &catalogInfo, + NULL, + NULL, + NULL); + + FolderInfo *folderInfo = reinterpret_cast(catalogInfo.finderInfo); + return folderInfo->finderFlags & kHasBundle; +} + #else static inline bool _q_isMacHidden(const char *nativePath) { @@ -473,17 +543,8 @@ bool QFileSystemEngine::fillMetaData(const QFileSystemEntry &entry, QFileSystemM #if defined(Q_OS_MACX) if (what & QFileSystemMetaData::BundleType) { - if (entryExists && data.isDirectory()) { - QCFType path = CFStringCreateWithBytes(0, - (const UInt8*)nativeFilePath, nativeFilePathLength, - kCFStringEncodingUTF8, false); - QCFType url = CFURLCreateWithFileSystemPath(0, path, - kCFURLPOSIXPathStyle, true); - - UInt32 type, creator; - if (CFBundleGetPackageInfoInDirectory(url, &type, &creator)) - data.entryFlags |= QFileSystemMetaData::BundleType; - } + if (entryExists && isPackage(data, entry)) + data.entryFlags |= QFileSystemMetaData::BundleType; data.knownFlagsMask |= QFileSystemMetaData::BundleType; }