Refactor OS X bundle detection for QFileInfo

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 <thiago.macieira@intel.com>
Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@digia.com>
This commit is contained in:
Samuel Gaist 2013-09-18 22:36:51 +02:00 committed by The Qt Project
parent dd864724b0
commit 72d60ea08c

View File

@ -1,5 +1,6 @@
/****************************************************************************
**
** Copyright (C) 2013 Samuel Gaist <samuel.gaist@edeltech.ch>>
** 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 <QtCore/private/qcore_mac_p.h>
# include <CoreFoundation/CFBundle.h>
#endif
QT_BEGIN_NAMESPACE
@ -78,6 +80,74 @@ static inline bool _q_isMacHidden(const char *nativePath)
FileInfo * const fileInfo = reinterpret_cast<FileInfo*>(&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<CFStringRef> path = CFStringCreateWithBytes(0,
reinterpret_cast<const UInt8*>(nativeFilePath),
nativeFilePathLength,
kCFStringEncodingUTF8,
false);
QCFType<CFURLRef> 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<CFURLRef> 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<FolderInfo *>(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<CFStringRef> path = CFStringCreateWithBytes(0,
(const UInt8*)nativeFilePath, nativeFilePathLength,
kCFStringEncodingUTF8, false);
QCFType<CFURLRef> 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;
}