diff options
Diffstat (limited to 'core/subsurfacesysinfo.cpp')
-rw-r--r-- | core/subsurfacesysinfo.cpp | 620 |
1 files changed, 620 insertions, 0 deletions
diff --git a/core/subsurfacesysinfo.cpp b/core/subsurfacesysinfo.cpp new file mode 100644 index 000000000..a7173b169 --- /dev/null +++ b/core/subsurfacesysinfo.cpp @@ -0,0 +1,620 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Intel Corporation +** Contact: http://www.qt-project.org/legal +** +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt 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 "subsurfacesysinfo.h" +#include <QString> + +#ifdef Q_OS_UNIX +#include <sys/utsname.h> +#endif + +#if QT_VERSION < QT_VERSION_CHECK(5, 4, 0) + +#ifndef QStringLiteral +# define QStringLiteral QString::fromUtf8 +#endif + +#ifdef Q_OS_UNIX +#include <qplatformdefs.h> +#endif + +#ifdef __APPLE__ +#include <CoreServices/CoreServices.h> +#endif + +// --- this is a copy of Qt 5.4's src/corelib/global/archdetect.cpp --- + +// main part: processor type +#if defined(Q_PROCESSOR_ALPHA) +# define ARCH_PROCESSOR "alpha" +#elif defined(Q_PROCESSOR_ARM) +# define ARCH_PROCESSOR "arm" +#elif defined(Q_PROCESSOR_AVR32) +# define ARCH_PROCESSOR "avr32" +#elif defined(Q_PROCESSOR_BLACKFIN) +# define ARCH_PROCESSOR "bfin" +#elif defined(Q_PROCESSOR_X86_32) +# define ARCH_PROCESSOR "i386" +#elif defined(Q_PROCESSOR_X86_64) +# define ARCH_PROCESSOR "x86_64" +#elif defined(Q_PROCESSOR_IA64) +# define ARCH_PROCESSOR "ia64" +#elif defined(Q_PROCESSOR_MIPS) +# define ARCH_PROCESSOR "mips" +#elif defined(Q_PROCESSOR_POWER) +# define ARCH_PROCESSOR "power" +#elif defined(Q_PROCESSOR_S390) +# define ARCH_PROCESSOR "s390" +#elif defined(Q_PROCESSOR_SH) +# define ARCH_PROCESSOR "sh" +#elif defined(Q_PROCESSOR_SPARC) +# define ARCH_PROCESSOR "sparc" +#else +# define ARCH_PROCESSOR "unknown" +#endif + +// endinanness +#if defined(Q_LITTLE_ENDIAN) +# define ARCH_ENDIANNESS "little_endian" +#elif defined(Q_BIG_ENDIAN) +# define ARCH_ENDIANNESS "big_endian" +#endif + +// pointer type +#if defined(Q_OS_WIN64) || (defined(Q_OS_WINRT) && defined(_M_X64)) +# define ARCH_POINTER "llp64" +#elif defined(__LP64__) || QT_POINTER_SIZE - 0 == 8 +# define ARCH_POINTER "lp64" +#else +# define ARCH_POINTER "ilp32" +#endif + +// secondary: ABI string (includes the dash) +#if defined(__ARM_EABI__) || defined(__mips_eabi) +# define ARCH_ABI1 "-eabi" +#elif defined(_MIPS_SIM) +# if _MIPS_SIM == _ABIO32 +# define ARCH_ABI1 "-o32" +# elif _MIPS_SIM == _ABIN32 +# define ARCH_ABI1 "-n32" +# elif _MIPS_SIM == _ABI64 +# define ARCH_ABI1 "-n64" +# elif _MIPS_SIM == _ABIO64 +# define ARCH_ABI1 "-o64" +# endif +#else +# define ARCH_ABI1 "" +#endif +#if defined(__ARM_PCS_VFP) || defined(__mips_hard_float) +# define ARCH_ABI2 "-hardfloat" +#else +# define ARCH_ABI2 "" +#endif + +#define ARCH_ABI ARCH_ABI1 ARCH_ABI2 + +#define ARCH_FULL ARCH_PROCESSOR "-" ARCH_ENDIANNESS "-" ARCH_POINTER ARCH_ABI + +// --- end of archdetect.cpp --- +// copied from Qt 5.4.1's src/corelib/global/qglobal.cpp + +#if defined(Q_OS_WIN) || defined(Q_OS_CYGWIN) || defined(Q_OS_WINCE) || defined(Q_OS_WINRT) + +QT_BEGIN_INCLUDE_NAMESPACE +#include "qt_windows.h" +QT_END_INCLUDE_NAMESPACE + +#ifndef Q_OS_WINRT +# ifndef Q_OS_WINCE +// Fallback for determining Windows versions >= 8 by looping using the +// version check macros. Note that it will return build number=0 to avoid +// inefficient looping. +static inline void determineWinOsVersionFallbackPost8(OSVERSIONINFO *result) +{ + result->dwBuildNumber = 0; + DWORDLONG conditionMask = 0; + VER_SET_CONDITION(conditionMask, VER_MAJORVERSION, VER_GREATER_EQUAL); + VER_SET_CONDITION(conditionMask, VER_PLATFORMID, VER_EQUAL); + OSVERSIONINFOEX checkVersion = { sizeof(OSVERSIONINFOEX), result->dwMajorVersion, 0, + result->dwBuildNumber, result->dwPlatformId, {'\0'}, 0, 0, 0, 0, 0 }; + for ( ; VerifyVersionInfo(&checkVersion, VER_MAJORVERSION | VER_PLATFORMID, conditionMask); ++checkVersion.dwMajorVersion) + result->dwMajorVersion = checkVersion.dwMajorVersion; + conditionMask = 0; + checkVersion.dwMajorVersion = result->dwMajorVersion; + checkVersion.dwMinorVersion = 0; + VER_SET_CONDITION(conditionMask, VER_MAJORVERSION, VER_EQUAL); + VER_SET_CONDITION(conditionMask, VER_MINORVERSION, VER_GREATER_EQUAL); + VER_SET_CONDITION(conditionMask, VER_PLATFORMID, VER_EQUAL); + for ( ; VerifyVersionInfo(&checkVersion, VER_MAJORVERSION | VER_MINORVERSION | VER_PLATFORMID, conditionMask); ++checkVersion.dwMinorVersion) + result->dwMinorVersion = checkVersion.dwMinorVersion; +} + +# endif // !Q_OS_WINCE + +static inline OSVERSIONINFO winOsVersion() +{ + OSVERSIONINFO result = { sizeof(OSVERSIONINFO), 0, 0, 0, 0, {'\0'}}; + // GetVersionEx() has been deprecated in Windows 8.1 and will return + // only Windows 8 from that version on. +# if defined(_MSC_VER) && _MSC_VER >= 1800 +# pragma warning( push ) +# pragma warning( disable : 4996 ) +# endif + GetVersionEx(&result); +# if defined(_MSC_VER) && _MSC_VER >= 1800 +# pragma warning( pop ) +# endif +# ifndef Q_OS_WINCE + if (result.dwMajorVersion == 6 && result.dwMinorVersion == 2) { + determineWinOsVersionFallbackPost8(&result); + } +# endif // !Q_OS_WINCE + return result; +} +#endif // !Q_OS_WINRT + +static const char *winVer_helper() +{ + switch (int(SubsurfaceSysInfo::WindowsVersion)) { + case SubsurfaceSysInfo::WV_NT: + return "NT"; + case SubsurfaceSysInfo::WV_2000: + return "2000"; + case SubsurfaceSysInfo::WV_XP: + return "XP"; + case SubsurfaceSysInfo::WV_2003: + return "2003"; + case SubsurfaceSysInfo::WV_VISTA: + return "Vista"; + case SubsurfaceSysInfo::WV_WINDOWS7: + return "7"; + case SubsurfaceSysInfo::WV_WINDOWS8: + return "8"; + case SubsurfaceSysInfo::WV_WINDOWS8_1: + return "8.1"; + + case SubsurfaceSysInfo::WV_CE: + return "CE"; + case SubsurfaceSysInfo::WV_CENET: + return "CENET"; + case SubsurfaceSysInfo::WV_CE_5: + return "CE5"; + case SubsurfaceSysInfo::WV_CE_6: + return "CE6"; + } + // unknown, future version + return 0; +} +#endif + +#if defined(Q_OS_UNIX) +# if (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)) || defined(Q_OS_FREEBSD) +# define USE_ETC_OS_RELEASE +struct QUnixOSVersion +{ + // from /etc/os-release + QString productType; // $ID + QString productVersion; // $VERSION_ID + QString prettyName; // $PRETTY_NAME +}; + +static QString unquote(const char *begin, const char *end) +{ + if (*begin == '"') { + Q_ASSERT(end[-1] == '"'); + return QString::fromLatin1(begin + 1, end - begin - 2); + } + return QString::fromLatin1(begin, end - begin); +} + +static bool readEtcOsRelease(QUnixOSVersion &v) +{ + // we're avoiding QFile here + int fd = QT_OPEN("/etc/os-release", O_RDONLY); + if (fd == -1) + return false; + + QT_STATBUF sbuf; + if (QT_FSTAT(fd, &sbuf) == -1) { + QT_CLOSE(fd); + return false; + } + + QByteArray buffer(sbuf.st_size, Qt::Uninitialized); + buffer.resize(QT_READ(fd, buffer.data(), sbuf.st_size)); + QT_CLOSE(fd); + + const char *ptr = buffer.constData(); + const char *end = buffer.constEnd(); + const char *eol; + for ( ; ptr != end; ptr = eol + 1) { + static const char idString[] = "ID="; + static const char prettyNameString[] = "PRETTY_NAME="; + static const char versionIdString[] = "VERSION_ID="; + + // find the end of the line after ptr + eol = static_cast<const char *>(memchr(ptr, '\n', end - ptr)); + if (!eol) + eol = end - 1; + + // note: we're doing a binary search here, so comparison + // must always be sorted + int cmp = strncmp(ptr, idString, strlen(idString)); + if (cmp < 0) + continue; + if (cmp == 0) { + ptr += strlen(idString); + v.productType = unquote(ptr, eol); + continue; + } + + cmp = strncmp(ptr, prettyNameString, strlen(prettyNameString)); + if (cmp < 0) + continue; + if (cmp == 0) { + ptr += strlen(prettyNameString); + v.prettyName = unquote(ptr, eol); + continue; + } + + cmp = strncmp(ptr, versionIdString, strlen(versionIdString)); + if (cmp < 0) + continue; + if (cmp == 0) { + ptr += strlen(versionIdString); + v.productVersion = unquote(ptr, eol); + continue; + } + } + + return true; +} +# endif // USE_ETC_OS_RELEASE +#endif // Q_OS_UNIX + +static QString unknownText() +{ + return QStringLiteral("unknown"); +} + +QString SubsurfaceSysInfo::buildCpuArchitecture() +{ + return QStringLiteral(ARCH_PROCESSOR); +} + +QString SubsurfaceSysInfo::currentCpuArchitecture() +{ +#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) + // We don't need to catch all the CPU architectures in this function; + // only those where the host CPU might be different than the build target + // (usually, 64-bit platforms). + SYSTEM_INFO info; + GetNativeSystemInfo(&info); + switch (info.wProcessorArchitecture) { +# ifdef PROCESSOR_ARCHITECTURE_AMD64 + case PROCESSOR_ARCHITECTURE_AMD64: + return QStringLiteral("x86_64"); +# endif +# ifdef PROCESSOR_ARCHITECTURE_IA32_ON_WIN64 + case PROCESSOR_ARCHITECTURE_IA32_ON_WIN64: +# endif + case PROCESSOR_ARCHITECTURE_IA64: + return QStringLiteral("ia64"); + } +#elif defined(Q_OS_UNIX) + long ret = -1; + struct utsname u; + +# if defined(Q_OS_SOLARIS) + // We need a special call for Solaris because uname(2) on x86 returns "i86pc" for + // both 32- and 64-bit CPUs. Reference: + // http://docs.oracle.com/cd/E18752_01/html/816-5167/sysinfo-2.html#REFMAN2sysinfo-2 + // http://fxr.watson.org/fxr/source/common/syscall/systeminfo.c?v=OPENSOLARIS + // http://fxr.watson.org/fxr/source/common/conf/param.c?v=OPENSOLARIS;im=10#L530 + if (ret == -1) + ret = sysinfo(SI_ARCHITECTURE_64, u.machine, sizeof u.machine); +# endif + + if (ret == -1) + ret = uname(&u); + + // we could use detectUnixVersion() above, but we only need a field no other function does + if (ret != -1) { + // the use of QT_BUILD_INTERNAL here is simply to ensure all branches build + // as we don't often build on some of the less common platforms +# if defined(Q_PROCESSOR_ARM) || defined(QT_BUILD_INTERNAL) + if (strcmp(u.machine, "aarch64") == 0) + return QStringLiteral("arm64"); + if (strncmp(u.machine, "armv", 4) == 0) + return QStringLiteral("arm"); +# endif +# if defined(Q_PROCESSOR_POWER) || defined(QT_BUILD_INTERNAL) + // harmonize "powerpc" and "ppc" to "power" + if (strncmp(u.machine, "ppc", 3) == 0) + return QLatin1String("power") + QLatin1String(u.machine + 3); + if (strncmp(u.machine, "powerpc", 7) == 0) + return QLatin1String("power") + QLatin1String(u.machine + 7); + if (strcmp(u.machine, "Power Macintosh") == 0) + return QLatin1String("power"); +# endif +# if defined(Q_PROCESSOR_SPARC) || defined(QT_BUILD_INTERNAL) + // Solaris sysinfo(2) (above) uses "sparcv9", but uname -m says "sun4u"; + // Linux says "sparc64" + if (strcmp(u.machine, "sun4u") == 0 || strcmp(u.machine, "sparc64") == 0) + return QStringLiteral("sparcv9"); + if (strcmp(u.machine, "sparc32") == 0) + return QStringLiteral("sparc"); +# endif +# if defined(Q_PROCESSOR_X86) || defined(QT_BUILD_INTERNAL) + // harmonize all "i?86" to "i386" + if (strlen(u.machine) == 4 && u.machine[0] == 'i' + && u.machine[2] == '8' && u.machine[3] == '6') + return QStringLiteral("i386"); + if (strcmp(u.machine, "amd64") == 0) // Solaris + return QStringLiteral("x86_64"); +# endif + return QString::fromLatin1(u.machine); + } +#endif + return buildCpuArchitecture(); +} + + +QString SubsurfaceSysInfo::buildAbi() +{ + return QLatin1String(ARCH_FULL); +} + +QString SubsurfaceSysInfo::kernelType() +{ +#if defined(Q_OS_WINCE) + return QStringLiteral("wince"); +#elif defined(Q_OS_WIN) + return QStringLiteral("winnt"); +#elif defined(Q_OS_UNIX) + struct utsname u; + if (uname(&u) == 0) + return QString::fromLatin1(u.sysname).toLower(); +#endif + return unknownText(); +} + +QString SubsurfaceSysInfo::kernelVersion() +{ +#ifdef Q_OS_WINRT + // TBD + return QString(); +#elif defined(Q_OS_WIN) + const OSVERSIONINFO osver = winOsVersion(); + return QString::number(int(osver.dwMajorVersion)) + QLatin1Char('.') + QString::number(int(osver.dwMinorVersion)) + + QLatin1Char('.') + QString::number(int(osver.dwBuildNumber)); +#else + struct utsname u; + if (uname(&u) == 0) + return QString::fromLatin1(u.release); + return QString(); +#endif +} + +QString SubsurfaceSysInfo::productType() +{ + // similar, but not identical to QFileSelectorPrivate::platformSelectors +#if defined(Q_OS_WINPHONE) + return QStringLiteral("winphone"); +#elif defined(Q_OS_WINRT) + return QStringLiteral("winrt"); +#elif defined(Q_OS_WINCE) + return QStringLiteral("wince"); +#elif defined(Q_OS_WIN) + return QStringLiteral("windows"); + +#elif defined(Q_OS_BLACKBERRY) + return QStringLiteral("blackberry"); +#elif defined(Q_OS_QNX) + return QStringLiteral("qnx"); + +#elif defined(Q_OS_ANDROID) + return QStringLiteral("android"); + +#elif defined(Q_OS_IOS) + return QStringLiteral("ios"); +#elif defined(Q_OS_OSX) + return QStringLiteral("osx"); +#elif defined(Q_OS_DARWIN) + return QStringLiteral("darwin"); + +#elif defined(USE_ETC_OS_RELEASE) // Q_OS_UNIX + QUnixOSVersion unixOsVersion; + readEtcOsRelease(unixOsVersion); + if (!unixOsVersion.productType.isEmpty()) + return unixOsVersion.productType; +#endif + return unknownText(); +} + +QString SubsurfaceSysInfo::productVersion() +{ +#if defined(Q_OS_IOS) + int major = (int(MacintoshVersion) >> 4) & 0xf; + int minor = int(MacintoshVersion) & 0xf; + if (Q_LIKELY(major < 10 && minor < 10)) { + char buf[4] = { char(major + '0'), '.', char(minor + '0'), '\0' }; + return QString::fromLatin1(buf, 3); + } + return QString::number(major) + QLatin1Char('.') + QString::number(minor); +#elif defined(Q_OS_OSX) + int minor = int(MacintoshVersion) - 2; // we're not running on Mac OS 9 + Q_ASSERT(minor < 100); + char buf[] = "10.0\0"; + if (Q_LIKELY(minor < 10)) { + buf[3] += minor; + } else { + buf[3] += minor / 10; + buf[4] = '0' + minor % 10; + } + return QString::fromLatin1(buf); +#elif defined(Q_OS_WIN) + const char *version = winVer_helper(); + if (version) + return QString::fromLatin1(version).toLower(); + // fall through + + // Android and Blackberry should not fall through to the Unix code +#elif defined(Q_OS_ANDROID) + // TBD +#elif defined(Q_OS_BLACKBERRY) + deviceinfo_details_t *deviceInfo; + if (deviceinfo_get_details(&deviceInfo) == BPS_SUCCESS) { + QString bbVersion = QString::fromLatin1(deviceinfo_details_get_device_os_version(deviceInfo)); + deviceinfo_free_details(&deviceInfo); + return bbVersion; + } +#elif defined(USE_ETC_OS_RELEASE) // Q_OS_UNIX + QUnixOSVersion unixOsVersion; + readEtcOsRelease(unixOsVersion); + if (!unixOsVersion.productVersion.isEmpty()) + return unixOsVersion.productVersion; +#endif + + // fallback + return unknownText(); +} + +QString SubsurfaceSysInfo::prettyProductName() +{ +#if defined(Q_OS_IOS) + return QLatin1String("iOS ") + productVersion(); +#elif defined(Q_OS_OSX) + // get the known codenames + const char *basename = 0; + switch (int(MacintoshVersion)) { + case MV_CHEETAH: + case MV_PUMA: + case MV_JAGUAR: + case MV_PANTHER: + case MV_TIGER: + // This version of Qt does not run on those versions of OS X + // so this case label will never be reached + Q_UNREACHABLE(); + break; + case MV_LEOPARD: + basename = "Mac OS X Leopard ("; + break; + case MV_SNOWLEOPARD: + basename = "Mac OS X Snow Leopard ("; + break; + case MV_LION: + basename = "Mac OS X Lion ("; + break; + case MV_MOUNTAINLION: + basename = "OS X Mountain Lion ("; + break; + case MV_MAVERICKS: + basename = "OS X Mavericks ("; + break; +#ifdef MV_YOSEMITE + case MV_YOSEMITE: +#else + case 0x000C: // MV_YOSEMITE +#endif + basename = "OS X Yosemite ("; + break; +#ifdef MV_ELCAPITAN + case MV_ELCAPITAN : +#else + case 0x000D: // MV_ELCAPITAN +#endif + basename = "OS X El Capitan ("; + break; + } + if (basename) + return QLatin1String(basename) + productVersion() + QLatin1Char(')'); + + // a future version of OS X + return QLatin1String("OS X ") + productVersion(); +#elif defined(Q_OS_WINPHONE) + return QLatin1String("Windows Phone ") + QLatin1String(winVer_helper()); +#elif defined(Q_OS_WIN) + return QLatin1String("Windows ") + QLatin1String(winVer_helper()); +#elif defined(Q_OS_ANDROID) + return QLatin1String("Android ") + productVersion(); +#elif defined(Q_OS_BLACKBERRY) + return QLatin1String("BlackBerry ") + productVersion(); +#elif defined(Q_OS_UNIX) +# ifdef USE_ETC_OS_RELEASE + QUnixOSVersion unixOsVersion; + readEtcOsRelease(unixOsVersion); + if (!unixOsVersion.prettyName.isEmpty()) + return unixOsVersion.prettyName; +# endif + struct utsname u; + if (uname(&u) == 0) + return QString::fromLatin1(u.sysname) + QLatin1Char(' ') + QString::fromLatin1(u.release); +#endif + return unknownText(); +} + +#endif // Qt >= 5.4 + +QString SubsurfaceSysInfo::prettyOsName() +{ + // Matches the pre-release version of Qt 5.4 + QString pretty = prettyProductName(); +#if defined(Q_OS_UNIX) && !defined(Q_OS_MAC) && !defined(Q_OS_ANDROID) + // QSysInfo::kernelType() returns lowercase ("linux" instead of "Linux") + struct utsname u; + if (uname(&u) == 0) + return QString::fromLatin1(u.sysname) + QLatin1String(" (") + pretty + QLatin1Char(')'); +#endif + return pretty; +} + +extern "C" { +bool isWin7Or8() +{ +#ifdef Q_OS_WIN + return (QSysInfo::WindowsVersion & QSysInfo::WV_NT_based) >= QSysInfo::WV_WINDOWS7; +#else + return false; +#endif +} +} |