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 }