File indexing completed on 2024-12-01 12:35:59
0001 /* 0002 This file is part of the KDE project 0003 SPDX-FileCopyrightText: 2000-2005 David Faure <faure@kde.org> 0004 SPDX-FileCopyrightText: 2007 Norbert Frese <nf2@scheinwelt.at> 0005 SPDX-FileCopyrightText: 2007 Thiago Macieira <thiago@kde.org> 0006 SPDX-FileCopyrightText: 2013-2014 Frank Reininghaus <frank78ac@googlemail.com> 0007 0008 SPDX-License-Identifier: LGPL-2.0-or-later 0009 */ 0010 0011 #include "udsentry.h" 0012 0013 #include "../utils_p.h" 0014 0015 #include <QDataStream> 0016 #include <QDebug> 0017 #include <QString> 0018 #include <QVector> 0019 0020 #include <KUser> 0021 0022 using namespace KIO; 0023 0024 // BEGIN UDSEntryPrivate 0025 /* ---------- UDSEntryPrivate ------------ */ 0026 0027 class KIO::UDSEntryPrivate : public QSharedData 0028 { 0029 public: 0030 void reserve(int size); 0031 void insert(uint udsField, const QString &value); 0032 void replace(uint udsField, const QString &value); 0033 void insert(uint udsField, long long value); 0034 void replace(uint udsField, long long value); 0035 int count() const; 0036 QString stringValue(uint udsField) const; 0037 long long numberValue(uint udsField, long long defaultValue = -1) const; 0038 #if KIOCORE_BUILD_DEPRECATED_SINCE(5, 8) 0039 QList<uint> listFields() const; 0040 #endif 0041 QVector<uint> fields() const; 0042 bool contains(uint udsField) const; 0043 void clear(); 0044 void save(QDataStream &s) const; 0045 void load(QDataStream &s); 0046 void debugUDSEntry(QDebug &stream) const; 0047 /** 0048 * @param field numeric UDS field id 0049 * @return the name of the field 0050 */ 0051 static QString nameOfUdsField(uint field); 0052 0053 private: 0054 struct Field { 0055 inline Field() 0056 { 0057 } 0058 inline Field(const uint index, const QString &value) 0059 : m_str(value) 0060 , m_index(index) 0061 { 0062 } 0063 inline Field(const uint index, long long value = 0) 0064 : m_long(value) 0065 , m_index(index) 0066 { 0067 } 0068 0069 QString m_str; 0070 long long m_long = LLONG_MIN; 0071 uint m_index = 0; 0072 }; 0073 std::vector<Field> storage; 0074 }; 0075 0076 void UDSEntryPrivate::reserve(int size) 0077 { 0078 storage.reserve(size); 0079 } 0080 0081 void UDSEntryPrivate::insert(uint udsField, const QString &value) 0082 { 0083 Q_ASSERT(udsField & KIO::UDSEntry::UDS_STRING); 0084 Q_ASSERT(std::find_if(storage.cbegin(), 0085 storage.cend(), 0086 [udsField](const Field &entry) { 0087 return entry.m_index == udsField; 0088 }) 0089 == storage.cend()); 0090 storage.emplace_back(udsField, value); 0091 } 0092 0093 void UDSEntryPrivate::replace(uint udsField, const QString &value) 0094 { 0095 Q_ASSERT(udsField & KIO::UDSEntry::UDS_STRING); 0096 auto it = std::find_if(storage.begin(), storage.end(), [udsField](const Field &entry) { 0097 return entry.m_index == udsField; 0098 }); 0099 if (it != storage.end()) { 0100 it->m_str = value; 0101 return; 0102 } 0103 storage.emplace_back(udsField, value); 0104 } 0105 0106 void UDSEntryPrivate::insert(uint udsField, long long value) 0107 { 0108 Q_ASSERT(udsField & KIO::UDSEntry::UDS_NUMBER); 0109 Q_ASSERT(std::find_if(storage.cbegin(), 0110 storage.cend(), 0111 [udsField](const Field &entry) { 0112 return entry.m_index == udsField; 0113 }) 0114 == storage.cend()); 0115 storage.emplace_back(udsField, value); 0116 } 0117 0118 void UDSEntryPrivate::replace(uint udsField, long long value) 0119 { 0120 Q_ASSERT(udsField & KIO::UDSEntry::UDS_NUMBER); 0121 auto it = std::find_if(storage.begin(), storage.end(), [udsField](const Field &entry) { 0122 return entry.m_index == udsField; 0123 }); 0124 if (it != storage.end()) { 0125 it->m_long = value; 0126 return; 0127 } 0128 storage.emplace_back(udsField, value); 0129 } 0130 0131 int UDSEntryPrivate::count() const 0132 { 0133 return storage.size(); 0134 } 0135 0136 QString UDSEntryPrivate::stringValue(uint udsField) const 0137 { 0138 auto it = std::find_if(storage.cbegin(), storage.cend(), [udsField](const Field &entry) { 0139 return entry.m_index == udsField; 0140 }); 0141 if (it != storage.cend()) { 0142 return it->m_str; 0143 } 0144 return QString(); 0145 } 0146 0147 long long UDSEntryPrivate::numberValue(uint udsField, long long defaultValue) const 0148 { 0149 auto it = std::find_if(storage.cbegin(), storage.cend(), [udsField](const Field &entry) { 0150 return entry.m_index == udsField; 0151 }); 0152 if (it != storage.cend()) { 0153 return it->m_long; 0154 } 0155 return defaultValue; 0156 } 0157 0158 #if KIOCORE_BUILD_DEPRECATED_SINCE(5, 8) 0159 QList<uint> UDSEntryPrivate::listFields() const 0160 { 0161 QList<uint> res; 0162 res.reserve(storage.size()); 0163 for (const Field &field : storage) { 0164 res.append(field.m_index); 0165 } 0166 return res; 0167 } 0168 #endif 0169 0170 QVector<uint> UDSEntryPrivate::fields() const 0171 { 0172 QVector<uint> res; 0173 res.reserve(storage.size()); 0174 for (const Field &field : storage) { 0175 res.append(field.m_index); 0176 } 0177 return res; 0178 } 0179 0180 bool UDSEntryPrivate::contains(uint udsField) const 0181 { 0182 auto it = std::find_if(storage.cbegin(), storage.cend(), [udsField](const Field &entry) { 0183 return entry.m_index == udsField; 0184 }); 0185 return (it != storage.cend()); 0186 } 0187 0188 void UDSEntryPrivate::clear() 0189 { 0190 storage.clear(); 0191 } 0192 0193 void UDSEntryPrivate::save(QDataStream &s) const 0194 { 0195 s << static_cast<quint32>(storage.size()); 0196 0197 for (const Field &field : storage) { 0198 uint uds = field.m_index; 0199 s << uds; 0200 0201 if (uds & KIO::UDSEntry::UDS_STRING) { 0202 s << field.m_str; 0203 } else if (uds & KIO::UDSEntry::UDS_NUMBER) { 0204 s << field.m_long; 0205 } else { 0206 Q_ASSERT_X(false, "KIO::UDSEntry", "Found a field with an invalid type"); 0207 } 0208 } 0209 } 0210 0211 void UDSEntryPrivate::load(QDataStream &s) 0212 { 0213 clear(); 0214 0215 quint32 size; 0216 s >> size; 0217 reserve(size); 0218 0219 // We cache the loaded strings. Some of them, like, e.g., the user, 0220 // will often be the same for many entries in a row. Caching them 0221 // permits to use implicit sharing to save memory. 0222 thread_local QVector<QString> cachedStrings; 0223 if (quint32(cachedStrings.size()) < size) { 0224 cachedStrings.resize(size); 0225 } 0226 0227 for (quint32 i = 0; i < size; ++i) { 0228 quint32 uds; 0229 s >> uds; 0230 0231 if (uds & KIO::UDSEntry::UDS_STRING) { 0232 // If the QString is the same like the one we read for the 0233 // previous UDSEntry at the i-th position, use an implicitly 0234 // shared copy of the same QString to save memory. 0235 QString buffer; 0236 s >> buffer; 0237 0238 if (buffer != cachedStrings.at(i)) { 0239 cachedStrings[i] = buffer; 0240 } 0241 0242 insert(uds, cachedStrings.at(i)); 0243 } else if (uds & KIO::UDSEntry::UDS_NUMBER) { 0244 long long value; 0245 s >> value; 0246 insert(uds, value); 0247 } else { 0248 Q_ASSERT_X(false, "KIO::UDSEntry", "Found a field with an invalid type"); 0249 } 0250 } 0251 } 0252 0253 QString UDSEntryPrivate::nameOfUdsField(uint field) 0254 { 0255 switch (field) { 0256 case UDSEntry::UDS_SIZE: 0257 return QStringLiteral("UDS_SIZE"); 0258 case UDSEntry::UDS_SIZE_LARGE: 0259 return QStringLiteral("UDS_SIZE_LARGE"); 0260 case UDSEntry::UDS_USER: 0261 return QStringLiteral("UDS_USER"); 0262 case UDSEntry::UDS_ICON_NAME: 0263 return QStringLiteral("UDS_ICON_NAME"); 0264 case UDSEntry::UDS_GROUP: 0265 return QStringLiteral("UDS_GROUP"); 0266 case UDSEntry::UDS_NAME: 0267 return QStringLiteral("UDS_NAME"); 0268 case UDSEntry::UDS_LOCAL_PATH: 0269 return QStringLiteral("UDS_LOCAL_PATH"); 0270 case UDSEntry::UDS_HIDDEN: 0271 return QStringLiteral("UDS_HIDDEN"); 0272 case UDSEntry::UDS_ACCESS: 0273 return QStringLiteral("UDS_ACCESS"); 0274 case UDSEntry::UDS_MODIFICATION_TIME: 0275 return QStringLiteral("UDS_MODIFICATION_TIME"); 0276 case UDSEntry::UDS_ACCESS_TIME: 0277 return QStringLiteral("UDS_ACCESS_TIME"); 0278 case UDSEntry::UDS_CREATION_TIME: 0279 return QStringLiteral("UDS_CREATION_TIME"); 0280 case UDSEntry::UDS_FILE_TYPE: 0281 return QStringLiteral("UDS_FILE_TYPE"); 0282 case UDSEntry::UDS_LINK_DEST: 0283 return QStringLiteral("UDS_LINK_DEST"); 0284 case UDSEntry::UDS_URL: 0285 return QStringLiteral("UDS_URL"); 0286 case UDSEntry::UDS_MIME_TYPE: 0287 return QStringLiteral("UDS_MIME_TYPE"); 0288 case UDSEntry::UDS_GUESSED_MIME_TYPE: 0289 return QStringLiteral("UDS_GUESSED_MIME_TYPE"); 0290 case UDSEntry::UDS_XML_PROPERTIES: 0291 return QStringLiteral("UDS_XML_PROPERTIES"); 0292 case UDSEntry::UDS_EXTENDED_ACL: 0293 return QStringLiteral("UDS_EXTENDED_ACL"); 0294 case UDSEntry::UDS_ACL_STRING: 0295 return QStringLiteral("UDS_ACL_STRING"); 0296 case UDSEntry::UDS_DEFAULT_ACL_STRING: 0297 return QStringLiteral("UDS_DEFAULT_ACL_STRING"); 0298 case UDSEntry::UDS_DISPLAY_NAME: 0299 return QStringLiteral("UDS_DISPLAY_NAME"); 0300 case UDSEntry::UDS_TARGET_URL: 0301 return QStringLiteral("UDS_TARGET_URL"); 0302 case UDSEntry::UDS_DISPLAY_TYPE: 0303 return QStringLiteral("UDS_DISPLAY_TYPE"); 0304 case UDSEntry::UDS_ICON_OVERLAY_NAMES: 0305 return QStringLiteral("UDS_ICON_OVERLAY_NAMES"); 0306 case UDSEntry::UDS_COMMENT: 0307 return QStringLiteral("UDS_COMMENT"); 0308 case UDSEntry::UDS_DEVICE_ID: 0309 return QStringLiteral("UDS_DEVICE_ID"); 0310 case UDSEntry::UDS_INODE: 0311 return QStringLiteral("UDS_INODE"); 0312 case UDSEntry::UDS_EXTRA: 0313 return QStringLiteral("UDS_EXTRA"); 0314 case UDSEntry::UDS_EXTRA_END: 0315 return QStringLiteral("UDS_EXTRA_END"); 0316 default: 0317 return QStringLiteral("Unknown uds field %1").arg(field); 0318 } 0319 } 0320 0321 void UDSEntryPrivate::debugUDSEntry(QDebug &stream) const 0322 { 0323 QDebugStateSaver saver(stream); 0324 stream.nospace() << "["; 0325 for (const Field &field : storage) { 0326 stream << " " << nameOfUdsField(field.m_index) << "="; 0327 if (field.m_index & KIO::UDSEntry::UDS_STRING) { 0328 stream << field.m_str; 0329 } else if (field.m_index & KIO::UDSEntry::UDS_NUMBER) { 0330 stream << field.m_long; 0331 } else { 0332 Q_ASSERT_X(false, "KIO::UDSEntry", "Found a field with an invalid type"); 0333 } 0334 } 0335 stream << " ]"; 0336 } 0337 // END UDSEntryPrivate 0338 0339 // BEGIN UDSEntry 0340 /* ---------- UDSEntry ------------ */ 0341 0342 UDSEntry::UDSEntry() 0343 : d(new UDSEntryPrivate()) 0344 { 0345 } 0346 0347 // BUG: this API doesn't allow to handle symlinks correctly (we need buff from QT_LSTAT for most things, but buff from QT_STAT for st_mode and st_size) 0348 UDSEntry::UDSEntry(const QT_STATBUF &buff, const QString &name) 0349 : d(new UDSEntryPrivate()) 0350 { 0351 #ifndef Q_OS_WIN 0352 d->reserve(10); 0353 #else 0354 d->reserve(8); 0355 #endif 0356 d->insert(UDS_NAME, name); 0357 d->insert(UDS_SIZE, buff.st_size); 0358 d->insert(UDS_DEVICE_ID, buff.st_dev); 0359 d->insert(UDS_INODE, buff.st_ino); 0360 d->insert(UDS_FILE_TYPE, buff.st_mode & QT_STAT_MASK); // extract file type 0361 d->insert(UDS_ACCESS, buff.st_mode & 07777); // extract permissions 0362 d->insert(UDS_MODIFICATION_TIME, buff.st_mtime); 0363 d->insert(UDS_ACCESS_TIME, buff.st_atime); 0364 #ifndef Q_OS_WIN 0365 d->insert(UDS_USER, KUser(buff.st_uid).loginName()); 0366 d->insert(UDS_GROUP, KUserGroup(buff.st_gid).name()); 0367 #endif 0368 } 0369 0370 UDSEntry::UDSEntry(const UDSEntry &) = default; 0371 UDSEntry::~UDSEntry() = default; 0372 UDSEntry::UDSEntry(UDSEntry &&) = default; 0373 UDSEntry &UDSEntry::operator=(const UDSEntry &) = default; 0374 UDSEntry &UDSEntry::operator=(UDSEntry &&) = default; 0375 0376 QString UDSEntry::stringValue(uint field) const 0377 { 0378 return d->stringValue(field); 0379 } 0380 0381 long long UDSEntry::numberValue(uint field, long long defaultValue) const 0382 { 0383 return d->numberValue(field, defaultValue); 0384 } 0385 0386 bool UDSEntry::isDir() const 0387 { 0388 return Utils::isDirMask(numberValue(UDS_FILE_TYPE)); 0389 } 0390 0391 bool UDSEntry::isLink() const 0392 { 0393 return !stringValue(UDS_LINK_DEST).isEmpty(); 0394 } 0395 0396 void UDSEntry::reserve(int size) 0397 { 0398 d->reserve(size); 0399 } 0400 0401 void UDSEntry::fastInsert(uint field, const QString &value) 0402 { 0403 d->insert(field, value); 0404 } 0405 0406 void UDSEntry::fastInsert(uint field, long long value) 0407 { 0408 d->insert(field, value); 0409 } 0410 0411 #if KIOCORE_BUILD_DEPRECATED_SINCE(5, 48) 0412 void UDSEntry::insert(uint field, const QString &value) 0413 { 0414 d->replace(field, value); 0415 } 0416 #endif 0417 0418 #if KIOCORE_BUILD_DEPRECATED_SINCE(5, 48) 0419 void UDSEntry::insert(uint field, long long value) 0420 { 0421 d->replace(field, value); 0422 } 0423 #endif 0424 0425 void UDSEntry::replace(uint field, const QString &value) 0426 { 0427 d->replace(field, value); 0428 } 0429 0430 void UDSEntry::replace(uint field, long long value) 0431 { 0432 d->replace(field, value); 0433 } 0434 0435 #if KIOCORE_BUILD_DEPRECATED_SINCE(5, 8) 0436 QList<uint> UDSEntry::listFields() const 0437 { 0438 return d->listFields(); 0439 } 0440 #endif 0441 0442 QVector<uint> UDSEntry::fields() const 0443 { 0444 return d->fields(); 0445 } 0446 0447 int UDSEntry::count() const 0448 { 0449 return d->count(); 0450 } 0451 0452 bool UDSEntry::contains(uint field) const 0453 { 0454 return d->contains(field); 0455 } 0456 0457 void UDSEntry::clear() 0458 { 0459 d->clear(); 0460 } 0461 // END UDSEntry 0462 0463 KIOCORE_EXPORT QDebug operator<<(QDebug stream, const KIO::UDSEntry &entry) 0464 { 0465 entry.d->debugUDSEntry(stream); 0466 return stream; 0467 } 0468 0469 KIOCORE_EXPORT QDataStream &operator<<(QDataStream &s, const KIO::UDSEntry &a) 0470 { 0471 a.d->save(s); 0472 return s; 0473 } 0474 0475 KIOCORE_EXPORT QDataStream &operator>>(QDataStream &s, KIO::UDSEntry &a) 0476 { 0477 a.d->load(s); 0478 return s; 0479 } 0480 0481 KIOCORE_EXPORT bool operator==(const KIO::UDSEntry &entry, const KIO::UDSEntry &other) 0482 { 0483 if (entry.count() != other.count()) { 0484 return false; 0485 } 0486 0487 const QVector<uint> fields = entry.fields(); 0488 for (uint field : fields) { 0489 if (!other.contains(field)) { 0490 return false; 0491 } 0492 0493 if (field & UDSEntry::UDS_STRING) { 0494 if (entry.stringValue(field) != other.stringValue(field)) { 0495 return false; 0496 } 0497 } else { 0498 if (entry.numberValue(field) != other.numberValue(field)) { 0499 return false; 0500 } 0501 } 0502 } 0503 0504 return true; 0505 } 0506 0507 KIOCORE_EXPORT bool operator!=(const KIO::UDSEntry &entry, const KIO::UDSEntry &other) 0508 { 0509 return !(entry == other); 0510 }