File indexing completed on 2024-05-26 04:05:33
0001 /* 0002 SPDX-FileCopyrightText: 2009 Harald Fernengel <harry@kdevelop.org> 0003 SPDX-FileCopyrightText: 2017 René J.V. Bertin <rjvbertin@gmail.com> 0004 0005 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL 0006 */ 0007 0008 #include <qdatetime.h> 0009 #include <qdebug.h> 0010 #include <qstring.h> 0011 #include <qstringlist.h> 0012 #include <qvariant.h> 0013 #include <qvarlengtharray.h> 0014 0015 #include <CoreFoundation/CoreFoundation.h> 0016 0017 #include <sys/sysctl.h> 0018 0019 /* helper classes to convert from CF types to Qt */ 0020 0021 static QString q_toString(const CFStringRef &str) 0022 { 0023 CFIndex length = CFStringGetLength(str); 0024 QVarLengthArray<UniChar> buffer(length); 0025 0026 CFRange range = {0, length}; 0027 CFStringGetCharacters(str, range, buffer.data()); 0028 return QString(reinterpret_cast<const QChar *>(buffer.data()), length); 0029 } 0030 0031 template<typename T> 0032 static inline T convertCFNumber(const CFNumberRef &num, CFNumberType type) 0033 { 0034 T n; 0035 CFNumberGetValue(num, type, &n); 0036 return n; 0037 } 0038 0039 static QVariant q_toVariant(const CFTypeRef &obj) 0040 { 0041 const CFTypeID typeId = CFGetTypeID(obj); 0042 0043 if (typeId == CFStringGetTypeID()) { 0044 return QVariant(q_toString(static_cast<const CFStringRef>(obj))); 0045 } 0046 0047 if (typeId == CFNumberGetTypeID()) { 0048 const CFNumberRef num = static_cast<const CFNumberRef>(obj); 0049 const CFNumberType type = CFNumberGetType(num); 0050 switch (type) { 0051 case kCFNumberSInt8Type: 0052 return QVariant::fromValue(convertCFNumber<char>(num, type)); 0053 case kCFNumberSInt16Type: 0054 return QVariant::fromValue(convertCFNumber<qint16>(num, type)); 0055 case kCFNumberSInt32Type: 0056 return QVariant::fromValue(convertCFNumber<qint32>(num, type)); 0057 case kCFNumberSInt64Type: 0058 return QVariant::fromValue(convertCFNumber<qint64>(num, type)); 0059 case kCFNumberCharType: 0060 return QVariant::fromValue(convertCFNumber<uchar>(num, type)); 0061 case kCFNumberShortType: 0062 return QVariant::fromValue(convertCFNumber<short>(num, type)); 0063 case kCFNumberIntType: 0064 return QVariant::fromValue(convertCFNumber<int>(num, type)); 0065 case kCFNumberLongType: 0066 return QVariant::fromValue(convertCFNumber<long>(num, type)); 0067 case kCFNumberLongLongType: 0068 return QVariant::fromValue(convertCFNumber<long long>(num, type)); 0069 case kCFNumberFloatType: 0070 return QVariant::fromValue(convertCFNumber<float>(num, type)); 0071 case kCFNumberDoubleType: 0072 return QVariant::fromValue(convertCFNumber<double>(num, type)); 0073 default: 0074 if (CFNumberIsFloatType(num)) { 0075 return QVariant::fromValue(convertCFNumber<double>(num, kCFNumberDoubleType)); 0076 } 0077 return QVariant::fromValue(convertCFNumber<quint64>(num, kCFNumberLongLongType)); 0078 } 0079 } 0080 0081 if (typeId == CFDateGetTypeID()) { 0082 QDateTime dt; 0083 dt.setSecsSinceEpoch(qint64(kCFAbsoluteTimeIntervalSince1970)); 0084 return dt.addSecs(int(CFDateGetAbsoluteTime(static_cast<const CFDateRef>(obj)))); 0085 } 0086 0087 if (typeId == CFDataGetTypeID()) { 0088 const CFDataRef cfdata = static_cast<const CFDataRef>(obj); 0089 return QByteArray(reinterpret_cast<const char *>(CFDataGetBytePtr(cfdata)), CFDataGetLength(cfdata)); 0090 } 0091 0092 if (typeId == CFBooleanGetTypeID()) { 0093 return QVariant(bool(CFBooleanGetValue(static_cast<const CFBooleanRef>(obj)))); 0094 } 0095 0096 if (typeId == CFArrayGetTypeID()) { 0097 const CFArrayRef cfarray = static_cast<const CFArrayRef>(obj); 0098 QList<QVariant> list; 0099 CFIndex size = CFArrayGetCount(cfarray); 0100 bool metNonString = false; 0101 for (CFIndex i = 0; i < size; ++i) { 0102 QVariant value = q_toVariant(CFArrayGetValueAtIndex(cfarray, i)); 0103 if (value.userType() != QMetaType::QString) { 0104 metNonString = true; 0105 } 0106 list << value; 0107 } 0108 if (metNonString) { 0109 return list; 0110 } else { 0111 return QVariant(list).toStringList(); 0112 } 0113 } 0114 0115 if (typeId == CFDictionaryGetTypeID()) { 0116 const CFDictionaryRef cfdict = static_cast<const CFDictionaryRef>(obj); 0117 const CFTypeID arrayTypeId = CFArrayGetTypeID(); 0118 int size = int(CFDictionaryGetCount(cfdict)); 0119 QVarLengthArray<CFPropertyListRef> keys(size); 0120 QVarLengthArray<CFPropertyListRef> values(size); 0121 CFDictionaryGetKeysAndValues(cfdict, keys.data(), values.data()); 0122 0123 QMultiMap<QString, QVariant> map; 0124 for (int i = 0; i < size; ++i) { 0125 QString key = q_toString(static_cast<const CFStringRef>(keys[i])); 0126 0127 if (CFGetTypeID(values[i]) == arrayTypeId) { 0128 const CFArrayRef cfarray = static_cast<const CFArrayRef>(values[i]); 0129 CFIndex arraySize = CFArrayGetCount(cfarray); 0130 for (CFIndex j = arraySize - 1; j >= 0; --j) { 0131 map.insert(key, q_toVariant(CFArrayGetValueAtIndex(cfarray, j))); 0132 } 0133 } else { 0134 map.insert(key, q_toVariant(values[i])); 0135 } 0136 } 0137 return QVariant::fromValue(map); 0138 } 0139 0140 return QVariant(); 0141 } 0142 0143 QMap<QString, QVariant> q_toVariantMap(const CFMutableDictionaryRef &dict) 0144 { 0145 Q_ASSERT(dict); 0146 0147 QMap<QString, QVariant> result; 0148 0149 const int count = CFDictionaryGetCount(dict); 0150 QVarLengthArray<void *> keys(count); 0151 QVarLengthArray<void *> values(count); 0152 0153 CFDictionaryGetKeysAndValues(dict, const_cast<const void **>(keys.data()), const_cast<const void **>(values.data())); 0154 0155 for (int i = 0; i < count; ++i) { 0156 const QString key = q_toString((CFStringRef)keys[i]); 0157 const QVariant value = q_toVariant((CFTypeRef)values[i]); 0158 result[key] = value; 0159 } 0160 0161 return result; 0162 } 0163 0164 bool q_sysctlbyname(const char *name, QString &result) 0165 { 0166 char *property = nullptr; 0167 size_t size = 0; 0168 int error = 0; 0169 if (name && sysctlbyname(name, nullptr, &size, nullptr, 0) == 0 && size > 0) { 0170 property = new char[size]; 0171 error = sysctlbyname(name, property, &size, nullptr, 0); 0172 if (!error) { 0173 result = QLatin1String(property); 0174 } 0175 delete[] property; 0176 } 0177 return !error; 0178 }