From b473c5f9cb3ee9364a93ea508132ea0d0999271a Mon Sep 17 00:00:00 2001 From: Sergey Fedorov Date: Sun, 18 Aug 2024 13:34:56 +0800 Subject: [PATCH 3/6] qlibrary.cpp: fix for macOS --- src/core/CMakeLists.txt | 1 + src/core/kernel/qcore_mac_p.cpp | 138 ++++++++++++++++++++++++++ src/core/kernel/qcore_mac_p.h | 169 ++++++++++++++++++++++++++++++++ src/core/plugin/qlibrary.cpp | 22 ++++- 4 files changed, 327 insertions(+), 3 deletions(-) create mode 100644 src/core/kernel/qcore_mac_p.cpp create mode 100644 src/core/kernel/qcore_mac_p.h diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index b5ff2a995..f6298e97e 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -152,6 +152,7 @@ set(CORE_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/kernel/qobject_p.h ${CMAKE_CURRENT_SOURCE_DIR}/kernel/qmath.h ${CMAKE_CURRENT_SOURCE_DIR}/kernel/qcore_unix_p.h + ${CMAKE_CURRENT_SOURCE_DIR}/kernel/qcore_mac_p.h ${CMAKE_CURRENT_SOURCE_DIR}/kernel/qeventdispatcher_unix_p.h ${CMAKE_CURRENT_SOURCE_DIR}/plugin/qpluginloader.h ${CMAKE_CURRENT_SOURCE_DIR}/plugin/qlibrary.h diff --git a/src/core/kernel/qcore_mac_p.cpp b/src/core/kernel/qcore_mac_p.cpp new file mode 100644 index 000000000..696e1f5aa --- /dev/null +++ b/src/core/kernel/qcore_mac_p.cpp @@ -0,0 +1,138 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include + +QT_BEGIN_NAMESPACE + +QString QCFString::toQString(CFStringRef str) +{ + if (!str) + return QString(); + + CFIndex length = CFStringGetLength(str); + if (length == 0) + return QString(); + + QString string(length, Qt::Uninitialized); + CFStringGetCharacters(str, CFRangeMake(0, length), reinterpret_cast(const_cast(string.unicode()))); + + return string; +} + +QCFString::operator QString() const +{ + if (string.isEmpty() && type) + const_cast(this)->string = toQString(type); + return string; +} + +CFStringRef QCFString::toCFStringRef(const QString &string) +{ + return CFStringCreateWithCharacters(0, reinterpret_cast(string.unicode()), + string.length()); +} + +QCFString::operator CFStringRef() const +{ + if (!type) { + if (string.d->data != string.d->array) + const_cast(this)->string.realloc(); // ### Qt5: do we really need this stupid user protection? + const_cast(this)->type = + CFStringCreateWithCharactersNoCopy(0, + reinterpret_cast(string.unicode()), + string.length(), + kCFAllocatorNull); + } + return type; +} + +void qt_mac_to_pascal_string(const QString &s, Str255 str, TextEncoding encoding, int len) +{ + if(len == -1) + len = s.length(); +#if 0 + UnicodeMapping mapping; + mapping.unicodeEncoding = CreateTextEncoding(kTextEncodingUnicodeDefault, + kTextEncodingDefaultVariant, + kUnicode16BitFormat); + mapping.otherEncoding = (encoding ? encoding : ); + mapping.mappingVersion = kUnicodeUseLatestMapping; + + UnicodeToTextInfo info; + OSStatus err = CreateUnicodeToTextInfo(&mapping, &info); + if(err != noErr) { + qDebug("Qt: internal: Unable to create pascal string '%s'::%d [%ld]", + s.left(len).latin1(), (int)encoding, err); + return; + } + const int unilen = len * 2; + const UniChar *unibuf = (UniChar *)s.unicode(); + ConvertFromUnicodeToPString(info, unilen, unibuf, str); + DisposeUnicodeToTextInfo(&info); +#else + Q_UNUSED(encoding); + CFStringGetPascalString(QCFString(s), str, 256, CFStringGetSystemEncoding()); +#endif +} + +QString qt_mac_from_pascal_string(const Str255 pstr) +{ + return QCFString(CFStringCreateWithPascalString(0, pstr, CFStringGetSystemEncoding())); +} + +OSErr qt_mac_create_fsref(const QString &file, FSRef *fsref) +{ + return FSPathMakeRef(reinterpret_cast(file.toUtf8().constData()), fsref, 0); +} + +// Don't use this function, it won't work in 10.5 (Leopard) and up +OSErr qt_mac_create_fsspec(const QString &file, FSSpec *spec) +{ + FSRef fsref; + OSErr ret = qt_mac_create_fsref(file, &fsref); + if (ret == noErr) + ret = FSGetCatalogInfo(&fsref, kFSCatInfoNone, 0, 0, spec, 0); + return ret; +} + +QT_END_NAMESPACE diff --git a/src/core/kernel/qcore_mac_p.h b/src/core/kernel/qcore_mac_p.h new file mode 100644 index 000000000..caa347a9e --- /dev/null +++ b/src/core/kernel/qcore_mac_p.h @@ -0,0 +1,169 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QCORE_MAC_P_H +#define QCORE_MAC_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#ifndef __IMAGECAPTURE__ +# define __IMAGECAPTURE__ +#endif + +#undef OLD_DEBUG +#ifdef DEBUG +# define OLD_DEBUG DEBUG +# undef DEBUG +#endif +#define DEBUG 0 +#ifdef qDebug +# define old_qDebug qDebug +# undef qDebug +#endif + +#if defined(QT_BUILD_QMAKE) || defined(QT_BOOTSTRAPPED) +#include +#else +#include +#endif + +#include + +#undef DEBUG +#ifdef OLD_DEBUG +# define DEBUG OLD_DEBUG +# undef OLD_DEBUG +#endif + +#ifdef old_qDebug +# undef qDebug +# define qDebug QT_NO_QDEBUG_MACRO +# undef old_qDebug +#endif + +#include "qstring.h" + +QT_BEGIN_NAMESPACE + +/* + Helper class that automates refernce counting for CFtypes. + After constructing the QCFType object, it can be copied like a + value-based type. + + Note that you must own the object you are wrapping. + This is typically the case if you get the object from a Core + Foundation function with the word "Create" or "Copy" in it. If + you got the object from a "Get" function, either retain it or use + constructFromGet(). One exception to this rule is the + HIThemeGet*Shape functions, which in reality are "Copy" functions. +*/ +template +class Q_CORE_EXPORT QCFType +{ +public: + inline QCFType(const T &t = 0) : type(t) {} + inline QCFType(const QCFType &helper) : type(helper.type) { if (type) CFRetain(type); } + inline ~QCFType() { if (type) CFRelease(type); } + inline operator T() { return type; } + inline QCFType operator =(const QCFType &helper) + { + if (helper.type) + CFRetain(helper.type); + CFTypeRef type2 = type; + type = helper.type; + if (type2) + CFRelease(type2); + return *this; + } + inline T *operator&() { return &type; } + template X as() const { return reinterpret_cast(type); } + static QCFType constructFromGet(const T &t) + { + CFRetain(t); + return QCFType(t); + } +protected: + T type; +}; + +class Q_CORE_EXPORT QCFString : public QCFType +{ +public: + inline QCFString(const QString &str) : QCFType(0), string(str) {} + inline QCFString(const CFStringRef cfstr = 0) : QCFType(cfstr) {} + inline QCFString(const QCFType &other) : QCFType(other) {} + operator QString() const; + operator CFStringRef() const; + static QString toQString(CFStringRef cfstr); + static CFStringRef toCFStringRef(const QString &str); +private: + QString string; +}; + +Q_CORE_EXPORT void qt_mac_to_pascal_string(const QString &s, Str255 str, TextEncoding encoding = 0, int len = -1); +Q_CORE_EXPORT QString qt_mac_from_pascal_string(const Str255 pstr); + +Q_CORE_EXPORT OSErr qt_mac_create_fsref(const QString &file, FSRef *fsref); +// Don't use this function, it won't work in 10.5 (Leopard) and up +Q_CORE_EXPORT OSErr qt_mac_create_fsspec(const QString &file, FSSpec *spec); + +QT_END_NAMESPACE + +#if (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_5) +#ifndef __LP64__ + typedef float CGFloat; + typedef int NSInteger; + typedef unsigned int NSUInteger; + #define SRefCon SInt32 + #define URefCon UInt32 +#endif +#endif + +#endif // QCORE_MAC_P_H diff --git a/src/core/plugin/qlibrary.cpp b/src/core/plugin/qlibrary.cpp index ea0ac6cac..6be3c2ead 100644 --- a/src/core/plugin/qlibrary.cpp +++ b/src/core/plugin/qlibrary.cpp @@ -34,9 +34,13 @@ #include "qcorecommon_p.h" #include "qcore_unix_p.h" +#ifdef Q_OS_MAC +# include +#endif + #include -#ifndef QT_NO_PLUGIN_CHECK +#if !defined(QT_NO_PLUGIN_CHECK) && !defined(Q_OS_MAC) # include # if QT_POINTER_SIZE == 8 # define QT_ELF_CLASS_TYPE ELFCLASS64 @@ -124,7 +128,7 @@ QT_BEGIN_NAMESPACE \sa loadHints */ -#ifndef QT_NO_PLUGIN_CHECK +#if !defined(QT_NO_PLUGIN_CHECK) && !defined(Q_OS_MAC) /* This opens the specified library and checks for the ELF magic and class. The advantage of this approach is that we can do verification without @@ -314,11 +318,23 @@ bool QLibrary::isLibrary(const QString &fileName) // libfoo-0.3.so // libfoo-0.3.so.0.3.0 +#ifdef Q_OS_MAC + QStringList suffixes = completeSuffix.split(QLatin1Char('.')); + const QString lastSuffix = suffixes.at(suffixes.count() - 1); + const QString firstSuffix = suffixes.at(0); + + bool valid = (lastSuffix == QLatin1String("dylib") + || firstSuffix == QLatin1String("so") + || firstSuffix == QLatin1String("bundle")); + + return valid; +#else foreach (const QString &suffix, completeSuffix.split(QLatin1Char('.'))) { if (suffix == QLatin1String("so")) { return true; }; } +#endif return false; } @@ -329,7 +345,7 @@ bool QLibraryPrivate::isPlugin() return (pluginState == QLibraryPrivate::IsAPlugin); } -#ifndef QT_NO_PLUGIN_CHECK +#if !defined(QT_NO_PLUGIN_CHECK) && !defined(Q_OS_MAC) if (Q_UNLIKELY(fileName.endsWith(QLatin1String(".debug")))) { // refuse to load a file that ends in .debug // these are the debug symbols from the libraries -- 2.49.0