1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtCore module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 #include "qoperatingsystemversion.h"
41 #if !defined(Q_OS_DARWIN) && !defined(Q_OS_WIN)
42 #include "qoperatingsystemversion_p.h"
43 #endif
44 
45 #if defined(Q_OS_DARWIN)
46 #include <QtCore/private/qcore_mac_p.h>
47 #endif
48 
49 #include <qversionnumber.h>
50 #include <qdebug.h>
51 
52 #if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED)
53 #include <private/qjni_p.h>
54 #endif
55 
56 QT_BEGIN_NAMESPACE
57 
58 /*!
59     \class QOperatingSystemVersion
60     \inmodule QtCore
61     \since 5.9
62     \brief The QOperatingSystemVersion class provides information about the
63     operating system version.
64 
65     Unlike other version functions in QSysInfo, QOperatingSystemVersion provides
66     access to the full version number that \a developers typically use to vary
67     behavior or determine whether to enable APIs or features based on the
68     operating system version (as opposed to the kernel version number or
69     marketing version).
70 
71     This class is also a complete replacement for QSysInfo::macVersion and
72     QSysInfo::windowsVersion, additionally providing access to the third (micro)
73     version number component.
74 
75     Presently, Android, Apple Platforms (iOS, macOS, tvOS, and watchOS),
76     and Windows are supported.
77 
78     The \a majorVersion(), \a minorVersion(), and \a microVersion() functions
79     return the parts of the operating system version number based on:
80 
81     \table
82         \header
83             \li Platforms
84             \li Value
85         \row
86             \li Android
87             \li result of parsing
88                 \l{https://developer.android.com/reference/android/os/Build.VERSION.html#RELEASE}{android.os.Build.VERSION.RELEASE}
89                 using QVersionNumber, with a fallback to
90                 \l{https://developer.android.com/reference/android/os/Build.VERSION.html#SDK_INT}{android.os.Build.VERSION.SDK_INT}
91                 to determine the major and minor version component if the former
92                 fails
93         \row
94             \li Apple Platforms
95             \li majorVersion, minorVersion, and patchVersion from
96                 \l{https://developer.apple.com/reference/foundation/nsprocessinfo/1410906-operatingsystemversion?language=objc}{NSProcessInfo.operatingSystemVersion}
97         \row
98             \li Windows
99             \li dwMajorVersion, dwMinorVersion, and dwBuildNumber from
100                 \l{https://msdn.microsoft.com/en-us/library/mt723418.aspx}{RtlGetVersion} -
101                 note that this function ALWAYS return the version number of the
102                 underlying operating system, as opposed to the shim underneath
103                 GetVersionEx that hides the real version number if the
104                 application is not manifested for that version of the OS
105     \endtable
106 
107     Because QOperatingSystemVersion stores both a version number and an OS type, the OS type
108     can be taken into account when performing comparisons. For example, on a macOS system running
109     macOS Sierra (v10.12), the following expression will return \c false even though the
110     major version number component of the object on the left hand side of the expression (10) is
111     greater than that of the object on the right (9):
112 
113     \snippet code/src_corelib_global_qoperatingsystemversion.cpp 0
114 
115     This allows expressions for multiple operating systems to be joined with a logical OR operator
116     and still work as expected. For example:
117 
118     \snippet code/src_corelib_global_qoperatingsystemversion.cpp 1
119 
120     A more naive comparison algorithm might incorrectly return true on all versions of macOS,
121     including Mac OS 9. This behavior is achieved by overloading the comparison operators to return
122     \c false whenever the OS types of the QOperatingSystemVersion instances being compared do not
123     match. Be aware that due to this it can be the case \c x >= y and \c x < y are BOTH \c false
124     for the same instances of \c x and \c y.
125 */
126 
127 /*!
128     \enum QOperatingSystemVersion::OSType
129 
130     This enum provides symbolic names for the various operating
131     system families supported by QOperatingSystemVersion.
132 
133     \value Android      The Google Android operating system.
134     \value IOS          The Apple iOS operating system.
135     \value MacOS        The Apple macOS operating system.
136     \value TvOS         The Apple tvOS operating system.
137     \value WatchOS      The Apple watchOS operating system.
138     \value Windows      The Microsoft Windows operating system.
139 
140     \value Unknown      An unknown or unsupported operating system.
141 */
142 
143 /*!
144     \fn QOperatingSystemVersion::QOperatingSystemVersion(OSType osType, int vmajor, int vminor = -1, int vmicro = -1)
145 
146     Constructs a QOperatingSystemVersion consisting of the OS type \a osType, and
147     major, minor, and micro version numbers \a vmajor, \a vminor and \a vmicro, respectively.
148 */
149 
150 /*!
151     \fn QOperatingSystemVersion QOperatingSystemVersion::current()
152 
153     Returns a QOperatingSystemVersion indicating the current OS and its version number.
154 
155     \sa currentType()
156 */
157 #if !defined(Q_OS_DARWIN) && !defined(Q_OS_WIN)
current()158 QOperatingSystemVersion QOperatingSystemVersion::current()
159 {
160     QOperatingSystemVersion version;
161     version.m_os = currentType();
162 #if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED)
163 #ifndef QT_BOOTSTRAPPED
164     const QVersionNumber v = QVersionNumber::fromString(QJNIObjectPrivate::getStaticObjectField(
165         "android/os/Build$VERSION", "RELEASE", "Ljava/lang/String;").toString());
166     if (!v.isNull()) {
167         version.m_major = v.majorVersion();
168         version.m_minor = v.minorVersion();
169         version.m_micro = v.microVersion();
170         return version;
171     }
172 #endif
173 
174     version.m_major = -1;
175     version.m_minor = -1;
176 
177     static const struct {
178         uint major : 4;
179         uint minor : 4;
180     } versions[] = {
181         { 1, 0 }, // API level 1
182         { 1, 1 }, // API level 2
183         { 1, 5 }, // API level 3
184         { 1, 6 }, // API level 4
185         { 2, 0 }, // API level 5
186         { 2, 0 }, // API level 6
187         { 2, 1 }, // API level 7
188         { 2, 2 }, // API level 8
189         { 2, 3 }, // API level 9
190         { 2, 3 }, // API level 10
191         { 3, 0 }, // API level 11
192         { 3, 1 }, // API level 12
193         { 3, 2 }, // API level 13
194         { 4, 0 }, // API level 14
195         { 4, 0 }, // API level 15
196         { 4, 1 }, // API level 16
197         { 4, 2 }, // API level 17
198         { 4, 3 }, // API level 18
199         { 4, 4 }, // API level 19
200         { 4, 4 }, // API level 20
201         { 5, 0 }, // API level 21
202         { 5, 1 }, // API level 22
203         { 6, 0 }, // API level 23
204         { 7, 0 }, // API level 24
205         { 7, 1 }, // API level 25
206         { 8, 0 }, // API level 26
207     };
208 
209     // This will give us at least the first 2 version components
210     const size_t versionIdx = size_t(QJNIObjectPrivate::getStaticField<jint>(
211         "android/os/Build$VERSION", "SDK_INT")) - 1;
212     if (versionIdx < sizeof(versions) / sizeof(versions[0])) {
213         version.m_major = versions[versionIdx].major;
214         version.m_minor = versions[versionIdx].minor;
215     }
216 
217     // API level 6 was exactly version 2.0.1
218     version.m_micro = versionIdx == 5 ? 1 : -1;
219 #else
220     version.m_major = -1;
221     version.m_minor = -1;
222     version.m_micro = -1;
223 #endif
224     return version;
225 }
226 #endif
227 
compareVersionComponents(int lhs,int rhs)228 static inline int compareVersionComponents(int lhs, int rhs)
229 {
230     return lhs >= 0 && rhs >= 0 ? lhs - rhs : 0;
231 }
232 
compare(const QOperatingSystemVersion & v1,const QOperatingSystemVersion & v2)233 int QOperatingSystemVersion::compare(const QOperatingSystemVersion &v1,
234                                      const QOperatingSystemVersion &v2)
235 {
236     if (v1.m_major == v2.m_major) {
237         if (v1.m_minor == v2.m_minor) {
238             return compareVersionComponents(v1.m_micro, v2.m_micro);
239         }
240         return compareVersionComponents(v1.m_minor, v2.m_minor);
241     }
242     return compareVersionComponents(v1.m_major, v2.m_major);
243 }
244 
245 /*!
246     \fn int QOperatingSystemVersion::majorVersion() const
247 
248     Returns the major version number, that is, the first segment of the
249     operating system's version number.
250 
251     See the main class documentation for what the major version number is on a given
252     operating system.
253 
254     -1 indicates an unknown or absent version number component.
255 
256     \sa minorVersion(), microVersion()
257 */
258 
259 /*!
260     \fn int QOperatingSystemVersion::minorVersion() const
261 
262     Returns the minor version number, that is, the second segment of the
263     operating system's version number.
264 
265     See the main class documentation for what the minor version number is on a given
266     operating system.
267 
268     -1 indicates an unknown or absent version number component.
269 
270     \sa majorVersion(), microVersion()
271 */
272 
273 /*!
274     \fn int QOperatingSystemVersion::microVersion() const
275 
276     Returns the micro version number, that is, the third segment of the
277     operating system's version number.
278 
279     See the main class documentation for what the micro version number is on a given
280     operating system.
281 
282     -1 indicates an unknown or absent version number component.
283 
284     \sa majorVersion(), minorVersion()
285 */
286 
287 /*!
288     \fn int QOperatingSystemVersion::segmentCount() const
289 
290     Returns the number of integers stored in the version number.
291 */
292 
293 /*!
294     \fn QOperatingSystemVersion::OSType QOperatingSystemVersion::type() const
295 
296     Returns the OS type identified by the QOperatingSystemVersion.
297 
298     \sa name()
299 */
300 
301 /*!
302     \fn QOperatingSystemVersion::OSType QOperatingSystemVersion::currentType()
303 
304     Returns the current OS type without constructing a QOperatingSystemVersion instance.
305 
306     \since 5.10
307 
308     \sa current()
309 */
310 
311 /*!
312     \fn QString QOperatingSystemVersion::name() const
313 
314     Returns a string representation of the OS type identified by the QOperatingSystemVersion.
315 
316     \sa type()
317 */
name() const318 QString QOperatingSystemVersion::name() const
319 {
320     switch (type()) {
321     case QOperatingSystemVersion::Windows:
322         return QStringLiteral("Windows");
323     case QOperatingSystemVersion::MacOS: {
324         if (majorVersion() < 10)
325             return QStringLiteral("Mac OS");
326         if (majorVersion() == 10 && minorVersion() < 8)
327             return QStringLiteral("Mac OS X");
328         if (majorVersion() == 10 && minorVersion() < 12)
329             return QStringLiteral("OS X");
330         return QStringLiteral("macOS");
331     }
332     case QOperatingSystemVersion::IOS: {
333         if (majorVersion() < 4)
334             return QStringLiteral("iPhone OS");
335         return QStringLiteral("iOS");
336     }
337     case QOperatingSystemVersion::TvOS:
338         return QStringLiteral("tvOS");
339     case QOperatingSystemVersion::WatchOS:
340         return QStringLiteral("watchOS");
341     case QOperatingSystemVersion::Android:
342         return QStringLiteral("Android");
343     case QOperatingSystemVersion::Unknown:
344     default:
345         return QString();
346     }
347 }
348 
349 /*!
350     \fn bool QOperatingSystemVersion::isAnyOfType(std::initializer_list<OSType> types) const
351 
352     Returns whether the OS type identified by the QOperatingSystemVersion
353     matches any of the OS types in \a types.
354 */
isAnyOfType(std::initializer_list<OSType> types) const355 bool QOperatingSystemVersion::isAnyOfType(std::initializer_list<OSType> types) const
356 {
357     for (const auto &t : qAsConst(types)) {
358         if (type() == t)
359             return true;
360     }
361     return false;
362 }
363 
364 /*!
365     \variable QOperatingSystemVersion::Windows7
366     \brief a version corresponding to Windows 7 (version 6.1).
367     \since 5.9
368  */
369 const QOperatingSystemVersion QOperatingSystemVersion::Windows7 =
370     QOperatingSystemVersion(QOperatingSystemVersion::Windows, 6, 1);
371 
372 /*!
373     \variable QOperatingSystemVersion::Windows8
374     \brief a version corresponding to Windows 8 (version 6.2).
375     \since 5.9
376  */
377 const QOperatingSystemVersion QOperatingSystemVersion::Windows8 =
378     QOperatingSystemVersion(QOperatingSystemVersion::Windows, 6, 2);
379 
380 /*!
381     \variable QOperatingSystemVersion::Windows8_1
382     \brief a version corresponding to Windows 8.1 (version 6.3).
383     \since 5.9
384  */
385 const QOperatingSystemVersion QOperatingSystemVersion::Windows8_1 =
386     QOperatingSystemVersion(QOperatingSystemVersion::Windows, 6, 3);
387 
388 /*!
389     \variable QOperatingSystemVersion::Windows10
390     \brief a version corresponding to Windows 10 (version 10.0).
391     \since 5.9
392  */
393 const QOperatingSystemVersion QOperatingSystemVersion::Windows10 =
394     QOperatingSystemVersion(QOperatingSystemVersion::Windows, 10);
395 
396 /*!
397     \variable QOperatingSystemVersion::OSXMavericks
398     \brief a version corresponding to OS X Mavericks (version 10.9).
399     \since 5.9
400  */
401 const QOperatingSystemVersion QOperatingSystemVersion::OSXMavericks =
402     QOperatingSystemVersion(QOperatingSystemVersion::MacOS, 10, 9);
403 
404 /*!
405     \variable QOperatingSystemVersion::OSXYosemite
406     \brief a version corresponding to OS X Yosemite (version 10.10).
407     \since 5.9
408  */
409 const QOperatingSystemVersion QOperatingSystemVersion::OSXYosemite =
410     QOperatingSystemVersion(QOperatingSystemVersion::MacOS, 10, 10);
411 
412 /*!
413     \variable QOperatingSystemVersion::OSXElCapitan
414     \brief a version corresponding to OS X El Capitan (version 10.11).
415     \since 5.9
416  */
417 const QOperatingSystemVersion QOperatingSystemVersion::OSXElCapitan =
418     QOperatingSystemVersion(QOperatingSystemVersion::MacOS, 10, 11);
419 
420 /*!
421     \variable QOperatingSystemVersion::MacOSSierra
422     \brief a version corresponding to macOS Sierra (version 10.12).
423     \since 5.9
424  */
425 const QOperatingSystemVersion QOperatingSystemVersion::MacOSSierra =
426     QOperatingSystemVersion(QOperatingSystemVersion::MacOS, 10, 12);
427 
428 /*!
429     \variable QOperatingSystemVersion::MacOSHighSierra
430     \brief a version corresponding to macOS High Sierra (version 10.13).
431     \since 5.9.1
432  */
433 const QOperatingSystemVersion QOperatingSystemVersion::MacOSHighSierra =
434     QOperatingSystemVersion(QOperatingSystemVersion::MacOS, 10, 13);
435 
436 /*!
437     \variable QOperatingSystemVersion::MacOSMojave
438     \brief a version corresponding to macOS Mojave (version 10.14).
439     \since 5.11.2
440  */
441 const QOperatingSystemVersion QOperatingSystemVersion::MacOSMojave =
442     QOperatingSystemVersion(QOperatingSystemVersion::MacOS, 10, 14);
443 
444 /*!
445     \variable QOperatingSystemVersion::MacOSCatalina
446     \brief a version corresponding to macOS Catalina (version 10.15).
447     \since 5.12.5
448  */
449 const QOperatingSystemVersion QOperatingSystemVersion::MacOSCatalina =
450     QOperatingSystemVersion(QOperatingSystemVersion::MacOS, 10, 15);
451 
452 /*!
453     \variable QOperatingSystemVersion::MacOSBigSur
454     \brief a version corresponding to macOS Big Sur
455 
456     The actual version number depends on whether the application was built
457     using the Xcode 12 SDK. If it was, the version number corresponds
458     to macOS 11.0. If not it will correspond to macOS 10.16.
459 
460     By comparing QOperatingSystemVersion::current() to this constant
461     you will always end up comparing to the right version number.
462     \since 6.0
463  */
__anon95c8dfdb0202null464 const QOperatingSystemVersion QOperatingSystemVersion::MacOSBigSur = [] {
465 #if defined(Q_OS_DARWIN)
466     if (QMacVersion::buildSDK(QMacVersion::ApplicationBinary) >= QOperatingSystemVersion(QOperatingSystemVersion::MacOS, 10, 16))
467         return QOperatingSystemVersion(QOperatingSystemVersion::MacOS, 11, 0);
468     else
469 #endif
470         return QOperatingSystemVersion(QOperatingSystemVersion::MacOS, 10, 16);
471 }();
472 
473 /*!
474     \variable QOperatingSystemVersion::AndroidJellyBean
475     \brief a version corresponding to Android Jelly Bean (version 4.1, API level 16).
476     \since 5.9
477  */
478 const QOperatingSystemVersion QOperatingSystemVersion::AndroidJellyBean =
479     QOperatingSystemVersion(QOperatingSystemVersion::Android, 4, 1);
480 
481 /*!
482     \variable QOperatingSystemVersion::AndroidJellyBean_MR1
483     \brief a version corresponding to Android Jelly Bean, maintenance release 1
484     (version 4.2, API level 17).
485     \since 5.9
486  */
487 const QOperatingSystemVersion QOperatingSystemVersion::AndroidJellyBean_MR1 =
488     QOperatingSystemVersion(QOperatingSystemVersion::Android, 4, 2);
489 
490 /*!
491     \variable QOperatingSystemVersion::AndroidJellyBean_MR2
492     \brief a version corresponding to Android Jelly Bean, maintenance release 2
493     (version 4.3, API level 18).
494     \since 5.9
495  */
496 const QOperatingSystemVersion QOperatingSystemVersion::AndroidJellyBean_MR2 =
497     QOperatingSystemVersion(QOperatingSystemVersion::Android, 4, 3);
498 
499 /*!
500     \variable QOperatingSystemVersion::AndroidKitKat
501     \brief a version corresponding to Android KitKat (versions 4.4 & 4.4W, API levels 19 & 20).
502     \since 5.9
503  */
504 const QOperatingSystemVersion QOperatingSystemVersion::AndroidKitKat =
505     QOperatingSystemVersion(QOperatingSystemVersion::Android, 4, 4);
506 
507 /*!
508     \variable QOperatingSystemVersion::AndroidLollipop
509     \brief a version corresponding to Android Lollipop (version 5.0, API level 21).
510     \since 5.9
511  */
512 const QOperatingSystemVersion QOperatingSystemVersion::AndroidLollipop =
513     QOperatingSystemVersion(QOperatingSystemVersion::Android, 5, 0);
514 
515 /*!
516     \variable QOperatingSystemVersion::AndroidLollipop_MR1
517     \brief a version corresponding to Android Lollipop, maintenance release 1
518     (version 5.1, API level 22).
519     \since 5.9
520  */
521 const QOperatingSystemVersion QOperatingSystemVersion::AndroidLollipop_MR1 =
522     QOperatingSystemVersion(QOperatingSystemVersion::Android, 5, 1);
523 
524 /*!
525     \variable QOperatingSystemVersion::AndroidMarshmallow
526     \brief a version corresponding to Android Marshmallow (version 6.0, API level 23).
527     \since 5.9
528  */
529 const QOperatingSystemVersion QOperatingSystemVersion::AndroidMarshmallow =
530     QOperatingSystemVersion(QOperatingSystemVersion::Android, 6, 0);
531 
532 /*!
533     \variable QOperatingSystemVersion::AndroidNougat
534     \brief a version corresponding to Android Nougat (version 7.0, API level 24).
535     \since 5.9
536  */
537 const QOperatingSystemVersion QOperatingSystemVersion::AndroidNougat =
538     QOperatingSystemVersion(QOperatingSystemVersion::Android, 7, 0);
539 
540 /*!
541     \variable QOperatingSystemVersion::AndroidNougat_MR1
542     \brief a version corresponding to Android Nougat, maintenance release 1
543     (version 7.0, API level 25).
544     \since 5.9
545  */
546 const QOperatingSystemVersion QOperatingSystemVersion::AndroidNougat_MR1 =
547     QOperatingSystemVersion(QOperatingSystemVersion::Android, 7, 1);
548 
549 /*!
550     \variable QOperatingSystemVersion::AndroidOreo
551     \brief a version corresponding to Android Oreo (version 8.0, API level 26).
552     \since 5.9.2
553  */
554 const QOperatingSystemVersion QOperatingSystemVersion::AndroidOreo =
555     QOperatingSystemVersion(QOperatingSystemVersion::Android, 8, 0);
556 
557 #ifndef QT_NO_DEBUG_STREAM
operator <<(QDebug debug,const QOperatingSystemVersion & ov)558 QDebug operator<<(QDebug debug, const QOperatingSystemVersion &ov)
559 {
560     QDebugStateSaver saver(debug);
561     debug.nospace();
562     debug << "QOperatingSystemVersion(" << ov.name()
563         << ", " << ov.majorVersion() << '.' << ov.minorVersion()
564         << '.' << ov.microVersion() << ')';
565     return debug;
566 }
567 #endif // !QT_NO_DEBUG_STREAM
568 
569 QT_END_NAMESPACE
570