1 /*
2 SPDX-FileCopyrightText: 2009 Harald Fernengel <harry@kdevelop.org>
3 SPDX-FileCopyrightText: 2017 René J.V. Bertin <rjvbertin@gmail.com>
4
5 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
6 */
7
8 #include <qdatetime.h>
9 #include <qdebug.h>
10 #include <qstring.h>
11 #include <qstringlist.h>
12 #include <qvariant.h>
13 #include <qvarlengtharray.h>
14
15 #include <CoreFoundation/CoreFoundation.h>
16
17 #include <sys/sysctl.h>
18
19 /* helper classes to convert from CF types to Qt */
20
q_toString(const CFStringRef & str)21 static QString q_toString(const CFStringRef &str)
22 {
23 CFIndex length = CFStringGetLength(str);
24 QVarLengthArray<UniChar> buffer(length);
25
26 CFRange range = {0, length};
27 CFStringGetCharacters(str, range, buffer.data());
28 return QString(reinterpret_cast<const QChar *>(buffer.data()), length);
29 }
30
31 template<typename T>
convertCFNumber(const CFNumberRef & num,CFNumberType type)32 static inline T convertCFNumber(const CFNumberRef &num, CFNumberType type)
33 {
34 T n;
35 CFNumberGetValue(num, type, &n);
36 return n;
37 }
38
q_toVariant(const CFTypeRef & obj)39 static QVariant q_toVariant(const CFTypeRef &obj)
40 {
41 const CFTypeID typeId = CFGetTypeID(obj);
42
43 if (typeId == CFStringGetTypeID()) {
44 return QVariant(q_toString(static_cast<const CFStringRef>(obj)));
45 }
46
47 if (typeId == CFNumberGetTypeID()) {
48 const CFNumberRef num = static_cast<const CFNumberRef>(obj);
49 const CFNumberType type = CFNumberGetType(num);
50 switch (type) {
51 case kCFNumberSInt8Type:
52 return QVariant::fromValue(convertCFNumber<char>(num, type));
53 case kCFNumberSInt16Type:
54 return QVariant::fromValue(convertCFNumber<qint16>(num, type));
55 case kCFNumberSInt32Type:
56 return QVariant::fromValue(convertCFNumber<qint32>(num, type));
57 case kCFNumberSInt64Type:
58 return QVariant::fromValue(convertCFNumber<qint64>(num, type));
59 case kCFNumberCharType:
60 return QVariant::fromValue(convertCFNumber<uchar>(num, type));
61 case kCFNumberShortType:
62 return QVariant::fromValue(convertCFNumber<short>(num, type));
63 case kCFNumberIntType:
64 return QVariant::fromValue(convertCFNumber<int>(num, type));
65 case kCFNumberLongType:
66 return QVariant::fromValue(convertCFNumber<long>(num, type));
67 case kCFNumberLongLongType:
68 return QVariant::fromValue(convertCFNumber<long long>(num, type));
69 case kCFNumberFloatType:
70 return QVariant::fromValue(convertCFNumber<float>(num, type));
71 case kCFNumberDoubleType:
72 return QVariant::fromValue(convertCFNumber<double>(num, type));
73 default:
74 if (CFNumberIsFloatType(num)) {
75 return QVariant::fromValue(convertCFNumber<double>(num, kCFNumberDoubleType));
76 }
77 return QVariant::fromValue(convertCFNumber<quint64>(num, kCFNumberLongLongType));
78 }
79 }
80
81 if (typeId == CFDateGetTypeID()) {
82 QDateTime dt;
83 dt.setSecsSinceEpoch(qint64(kCFAbsoluteTimeIntervalSince1970));
84 return dt.addSecs(int(CFDateGetAbsoluteTime(static_cast<const CFDateRef>(obj))));
85 }
86
87 if (typeId == CFDataGetTypeID()) {
88 const CFDataRef cfdata = static_cast<const CFDataRef>(obj);
89 return QByteArray(reinterpret_cast<const char *>(CFDataGetBytePtr(cfdata)), CFDataGetLength(cfdata));
90 }
91
92 if (typeId == CFBooleanGetTypeID()) {
93 return QVariant(bool(CFBooleanGetValue(static_cast<const CFBooleanRef>(obj))));
94 }
95
96 if (typeId == CFArrayGetTypeID()) {
97 const CFArrayRef cfarray = static_cast<const CFArrayRef>(obj);
98 QList<QVariant> list;
99 CFIndex size = CFArrayGetCount(cfarray);
100 bool metNonString = false;
101 for (CFIndex i = 0; i < size; ++i) {
102 QVariant value = q_toVariant(CFArrayGetValueAtIndex(cfarray, i));
103 if (value.type() != QVariant::String) {
104 metNonString = true;
105 }
106 list << value;
107 }
108 if (metNonString) {
109 return list;
110 } else {
111 return QVariant(list).toStringList();
112 }
113 }
114
115 if (typeId == CFDictionaryGetTypeID()) {
116 const CFDictionaryRef cfdict = static_cast<const CFDictionaryRef>(obj);
117 const CFTypeID arrayTypeId = CFArrayGetTypeID();
118 int size = int(CFDictionaryGetCount(cfdict));
119 QVarLengthArray<CFPropertyListRef> keys(size);
120 QVarLengthArray<CFPropertyListRef> values(size);
121 CFDictionaryGetKeysAndValues(cfdict, keys.data(), values.data());
122
123 QMultiMap<QString, QVariant> map;
124 for (int i = 0; i < size; ++i) {
125 QString key = q_toString(static_cast<const CFStringRef>(keys[i]));
126
127 if (CFGetTypeID(values[i]) == arrayTypeId) {
128 const CFArrayRef cfarray = static_cast<const CFArrayRef>(values[i]);
129 CFIndex arraySize = CFArrayGetCount(cfarray);
130 for (CFIndex j = arraySize - 1; j >= 0; --j) {
131 map.insert(key, q_toVariant(CFArrayGetValueAtIndex(cfarray, j)));
132 }
133 } else {
134 map.insert(key, q_toVariant(values[i]));
135 }
136 }
137 return map;
138 }
139
140 return QVariant();
141 }
142
q_toVariantMap(const CFMutableDictionaryRef & dict)143 QMap<QString, QVariant> q_toVariantMap(const CFMutableDictionaryRef &dict)
144 {
145 Q_ASSERT(dict);
146
147 QMap<QString, QVariant> result;
148
149 const int count = CFDictionaryGetCount(dict);
150 QVarLengthArray<void *> keys(count);
151 QVarLengthArray<void *> values(count);
152
153 CFDictionaryGetKeysAndValues(dict, const_cast<const void **>(keys.data()), const_cast<const void **>(values.data()));
154
155 for (int i = 0; i < count; ++i) {
156 const QString key = q_toString((CFStringRef)keys[i]);
157 const QVariant value = q_toVariant((CFTypeRef)values[i]);
158 result[key] = value;
159 }
160
161 return result;
162 }
163
q_sysctlbyname(const char * name,QString & result)164 bool q_sysctlbyname(const char *name, QString &result)
165 {
166 char *property = nullptr;
167 size_t size = 0;
168 int error = 0;
169 if (name && sysctlbyname(name, nullptr, &size, nullptr, 0) == 0 && size > 0) {
170 property = new char[size];
171 error = sysctlbyname(name, property, &size, nullptr, 0);
172 if (!error) {
173 result = QLatin1String(property);
174 }
175 delete[] property;
176 }
177 return !error;
178 }
179