KIO

udsentry.cpp
1/*
2 This file is part of the KDE project
3 SPDX-FileCopyrightText: 2000-2005 David Faure <faure@kde.org>
4 SPDX-FileCopyrightText: 2007 Norbert Frese <nf2@scheinwelt.at>
5 SPDX-FileCopyrightText: 2007 Thiago Macieira <thiago@kde.org>
6 SPDX-FileCopyrightText: 2013-2014 Frank Reininghaus <frank78ac@googlemail.com>
7
8 SPDX-License-Identifier: LGPL-2.0-or-later
9*/
10
11#include "udsentry.h"
12
13#include "../utils_p.h"
14
15#include <QDataStream>
16#include <QDebug>
17#include <QList>
18#include <QString>
19
20#include <KUser>
21
22using namespace KIO;
23
24// BEGIN UDSEntryPrivate
25/* ---------- UDSEntryPrivate ------------ */
26
27class KIO::UDSEntryPrivate : public QSharedData
28{
29public:
30 void reserve(int size);
31 void insert(uint udsField, const QString &value);
32 void replace(uint udsField, const QString &value);
33 void insert(uint udsField, long long value);
34 void replace(uint udsField, long long value);
35 int count() const;
36 QString stringValue(uint udsField) const;
37 long long numberValue(uint udsField, long long defaultValue = -1) const;
38 QList<uint> fields() const;
39 bool contains(uint udsField) const;
40 void clear();
41 void save(QDataStream &s) const;
42 void load(QDataStream &s);
43 void debugUDSEntry(QDebug &stream) const;
44 /**
45 * @param field numeric UDS field id
46 * @return the name of the field
47 */
48 static QString nameOfUdsField(uint field);
49
50private:
51 struct Field {
52 inline Field()
53 {
54 }
55 inline Field(const uint index, const QString &value)
56 : m_str(value)
57 , m_index(index)
58 {
59 }
60 inline Field(const uint index, long long value = 0)
61 : m_long(value)
62 , m_index(index)
63 {
64 }
65
66 QString m_str;
67 long long m_long = LLONG_MIN;
68 uint m_index = 0;
69 };
70 std::vector<Field> storage;
71};
72
73void UDSEntryPrivate::reserve(int size)
74{
75 storage.reserve(size);
76}
77
78void UDSEntryPrivate::insert(uint udsField, const QString &value)
79{
80 Q_ASSERT(udsField & KIO::UDSEntry::UDS_STRING);
81 Q_ASSERT(std::find_if(storage.cbegin(),
82 storage.cend(),
83 [udsField](const Field &entry) {
84 return entry.m_index == udsField;
85 })
86 == storage.cend());
87 storage.emplace_back(udsField, value);
88}
89
90void UDSEntryPrivate::replace(uint udsField, const QString &value)
91{
92 Q_ASSERT(udsField & KIO::UDSEntry::UDS_STRING);
93 auto it = std::find_if(storage.begin(), storage.end(), [udsField](const Field &entry) {
94 return entry.m_index == udsField;
95 });
96 if (it != storage.end()) {
97 it->m_str = value;
98 return;
99 }
100 storage.emplace_back(udsField, value);
101}
102
103void UDSEntryPrivate::insert(uint udsField, long long value)
104{
105 Q_ASSERT(udsField & KIO::UDSEntry::UDS_NUMBER);
106 Q_ASSERT(std::find_if(storage.cbegin(),
107 storage.cend(),
108 [udsField](const Field &entry) {
109 return entry.m_index == udsField;
110 })
111 == storage.cend());
112 storage.emplace_back(udsField, value);
113}
114
115void UDSEntryPrivate::replace(uint udsField, long long value)
116{
117 Q_ASSERT(udsField & KIO::UDSEntry::UDS_NUMBER);
118 auto it = std::find_if(storage.begin(), storage.end(), [udsField](const Field &entry) {
119 return entry.m_index == udsField;
120 });
121 if (it != storage.end()) {
122 it->m_long = value;
123 return;
124 }
125 storage.emplace_back(udsField, value);
126}
127
128int UDSEntryPrivate::count() const
129{
130 return storage.size();
131}
132
133QString UDSEntryPrivate::stringValue(uint udsField) const
134{
135 auto it = std::find_if(storage.cbegin(), storage.cend(), [udsField](const Field &entry) {
136 return entry.m_index == udsField;
137 });
138 if (it != storage.cend()) {
139 return it->m_str;
140 }
141 return QString();
142}
143
144long long UDSEntryPrivate::numberValue(uint udsField, long long defaultValue) const
145{
146 auto it = std::find_if(storage.cbegin(), storage.cend(), [udsField](const Field &entry) {
147 return entry.m_index == udsField;
148 });
149 if (it != storage.cend()) {
150 return it->m_long;
151 }
152 return defaultValue;
153}
154
155QList<uint> UDSEntryPrivate::fields() const
156{
157 QList<uint> res;
158 res.reserve(storage.size());
159 for (const Field &field : storage) {
160 res.append(field.m_index);
161 }
162 return res;
163}
164
165bool UDSEntryPrivate::contains(uint udsField) const
166{
167 auto it = std::find_if(storage.cbegin(), storage.cend(), [udsField](const Field &entry) {
168 return entry.m_index == udsField;
169 });
170 return (it != storage.cend());
171}
172
173void UDSEntryPrivate::clear()
174{
175 storage.clear();
176}
177
178void UDSEntryPrivate::save(QDataStream &s) const
179{
180 s << static_cast<quint32>(storage.size());
181
182 for (const Field &field : storage) {
183 uint uds = field.m_index;
184 s << uds;
185
186 if (uds & KIO::UDSEntry::UDS_STRING) {
187 s << field.m_str;
188 } else if (uds & KIO::UDSEntry::UDS_NUMBER) {
189 s << field.m_long;
190 } else {
191 Q_ASSERT_X(false, "KIO::UDSEntry", "Found a field with an invalid type");
192 }
193 }
194}
195
196void UDSEntryPrivate::load(QDataStream &s)
197{
198 clear();
199
200 quint32 size;
201 s >> size;
202 reserve(size);
203
204 // We cache the loaded strings. Some of them, like, e.g., the user,
205 // will often be the same for many entries in a row. Caching them
206 // permits to use implicit sharing to save memory.
207 thread_local QList<QString> cachedStrings;
208 if (quint32(cachedStrings.size()) < size) {
209 cachedStrings.resize(size);
210 }
211
212 for (quint32 i = 0; i < size; ++i) {
213 quint32 uds;
214 s >> uds;
215
216 if (uds & KIO::UDSEntry::UDS_STRING) {
217 // If the QString is the same like the one we read for the
218 // previous UDSEntry at the i-th position, use an implicitly
219 // shared copy of the same QString to save memory.
220 QString buffer;
221 s >> buffer;
222
223 if (buffer != cachedStrings.at(i)) {
224 cachedStrings[i] = buffer;
225 }
226
227 insert(uds, cachedStrings.at(i));
228 } else if (uds & KIO::UDSEntry::UDS_NUMBER) {
229 long long value;
230 s >> value;
231 insert(uds, value);
232 } else {
233 Q_ASSERT_X(false, "KIO::UDSEntry", "Found a field with an invalid type");
234 }
235 }
236}
237
238QString UDSEntryPrivate::nameOfUdsField(uint field)
239{
240 switch (field) {
242 return QStringLiteral("UDS_SIZE");
244 return QStringLiteral("UDS_SIZE_LARGE");
246 return QStringLiteral("UDS_USER");
248 return QStringLiteral("UDS_ICON_NAME");
250 return QStringLiteral("UDS_GROUP");
252 return QStringLiteral("UDS_NAME");
254 return QStringLiteral("UDS_LOCAL_GROUP_ID");
256 return QStringLiteral("UDS_LOCAL_USER_ID");
258 return QStringLiteral("UDS_LOCAL_PATH");
260 return QStringLiteral("UDS_HIDDEN");
262 return QStringLiteral("UDS_ACCESS");
264 return QStringLiteral("UDS_MODIFICATION_TIME");
266 return QStringLiteral("UDS_ACCESS_TIME");
268 return QStringLiteral("UDS_CREATION_TIME");
270 return QStringLiteral("UDS_FILE_TYPE");
272 return QStringLiteral("UDS_LINK_DEST");
274 return QStringLiteral("UDS_URL");
276 return QStringLiteral("UDS_MIME_TYPE");
278 return QStringLiteral("UDS_GUESSED_MIME_TYPE");
280 return QStringLiteral("UDS_XML_PROPERTIES");
282 return QStringLiteral("UDS_EXTENDED_ACL");
284 return QStringLiteral("UDS_ACL_STRING");
286 return QStringLiteral("UDS_DEFAULT_ACL_STRING");
288 return QStringLiteral("UDS_DISPLAY_NAME");
290 return QStringLiteral("UDS_TARGET_URL");
292 return QStringLiteral("UDS_DISPLAY_TYPE");
294 return QStringLiteral("UDS_ICON_OVERLAY_NAMES");
296 return QStringLiteral("UDS_COMMENT");
298 return QStringLiteral("UDS_DEVICE_ID");
300 return QStringLiteral("UDS_INODE");
302 return QStringLiteral("UDS_EXTRA");
304 return QStringLiteral("UDS_EXTRA_END");
305 default:
306 return QStringLiteral("Unknown uds field %1").arg(field);
307 }
308}
309
310void UDSEntryPrivate::debugUDSEntry(QDebug &stream) const
311{
312 QDebugStateSaver saver(stream);
313 stream.nospace() << "[";
314 for (const Field &field : storage) {
315 stream << " " << nameOfUdsField(field.m_index) << "=";
316 if (field.m_index & KIO::UDSEntry::UDS_STRING) {
317 stream << field.m_str;
318 } else if (field.m_index & KIO::UDSEntry::UDS_NUMBER) {
319 stream << field.m_long;
320 } else {
321 Q_ASSERT_X(false, "KIO::UDSEntry", "Found a field with an invalid type");
322 }
323 }
324 stream << " ]";
325}
326// END UDSEntryPrivate
327
328// BEGIN UDSEntry
329/* ---------- UDSEntry ------------ */
330
331UDSEntry::UDSEntry()
332 : d(new UDSEntryPrivate())
333{
334}
335
336// 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)
337UDSEntry::UDSEntry(const QT_STATBUF &buff, const QString &name)
338 : d(new UDSEntryPrivate())
339{
340#ifndef Q_OS_WIN
341 d->reserve(10);
342#else
343 d->reserve(8);
344#endif
345 d->insert(UDS_NAME, name);
346 d->insert(UDS_SIZE, buff.st_size);
347 d->insert(UDS_DEVICE_ID, buff.st_dev);
348 d->insert(UDS_INODE, buff.st_ino);
349 d->insert(UDS_FILE_TYPE, buff.st_mode & QT_STAT_MASK); // extract file type
350 d->insert(UDS_ACCESS, buff.st_mode & 07777); // extract permissions
351 d->insert(UDS_MODIFICATION_TIME, buff.st_mtime);
352 d->insert(UDS_ACCESS_TIME, buff.st_atime);
353#ifndef Q_OS_WIN
354 d->insert(UDS_LOCAL_USER_ID, buff.st_uid);
355 d->insert(UDS_LOCAL_GROUP_ID, buff.st_gid);
356#endif
357}
358
359UDSEntry::UDSEntry(const UDSEntry &) = default;
360UDSEntry::~UDSEntry() = default;
361UDSEntry::UDSEntry(UDSEntry &&) = default;
362UDSEntry &UDSEntry::operator=(const UDSEntry &) = default;
364
366{
367 return d->stringValue(field);
368}
369
370long long UDSEntry::numberValue(uint field, long long defaultValue) const
371{
372 return d->numberValue(field, defaultValue);
373}
374
375bool UDSEntry::isDir() const
376{
377 return Utils::isDirMask(numberValue(UDS_FILE_TYPE));
378}
379
381{
383}
384
385void UDSEntry::reserve(int size)
386{
387 d->reserve(size);
388}
389
390void UDSEntry::fastInsert(uint field, const QString &value)
391{
392 d->insert(field, value);
393}
394
395void UDSEntry::fastInsert(uint field, long long value)
396{
397 d->insert(field, value);
398}
399
400void UDSEntry::replace(uint field, const QString &value)
401{
402 d->replace(field, value);
403}
404
405void UDSEntry::replace(uint field, long long value)
406{
407 d->replace(field, value);
408}
409
411{
412 return d->fields();
413}
414
416{
417 return d->count();
418}
419
420bool UDSEntry::contains(uint field) const
421{
422 return d->contains(field);
423}
424
426{
427 d->clear();
428}
429// END UDSEntry
430
431KIOCORE_EXPORT QDebug operator<<(QDebug stream, const KIO::UDSEntry &entry)
432{
433 entry.d->debugUDSEntry(stream);
434 return stream;
435}
436
437KIOCORE_EXPORT QDataStream &operator<<(QDataStream &s, const KIO::UDSEntry &a)
438{
439 a.d->save(s);
440 return s;
441}
442
443KIOCORE_EXPORT QDataStream &operator>>(QDataStream &s, KIO::UDSEntry &a)
444{
445 a.d->load(s);
446 return s;
447}
448
449// TODO KF7 remove
450// legacy operator in global namespace for binary compatibility
451KIOCORE_EXPORT bool operator==(const KIO::UDSEntry &entry, const KIO::UDSEntry &other)
452{
453 return KIO::operator==(entry, other);
454}
455
456// TODO KF7 remove
457// legacy operator in global namespace for binary compatibility
458KIOCORE_EXPORT bool operator!=(const KIO::UDSEntry &entry, const KIO::UDSEntry &other)
459{
460 return KIO::operator!=(entry, other);
461}
462
463bool KIO::operator==(const KIO::UDSEntry &entry, const KIO::UDSEntry &other)
464{
465 if (entry.count() != other.count()) {
466 return false;
467 }
468
469 const QList<uint> fields = entry.fields();
470 for (uint field : fields) {
471 if (!other.contains(field)) {
472 return false;
473 }
474
475 if (field & UDSEntry::UDS_STRING) {
476 if (entry.stringValue(field) != other.stringValue(field)) {
477 return false;
478 }
479 } else {
480 if (entry.numberValue(field) != other.numberValue(field)) {
481 return false;
482 }
483 }
484 }
485
486 return true;
487}
488
489bool KIO::operator!=(const KIO::UDSEntry &entry, const KIO::UDSEntry &other)
490{
491 return !KIO::operator==(entry, other);
492}
Universal Directory Service.
QList< uint > fields() const
A vector of fields being present for the current entry.
Definition udsentry.cpp:410
void reserve(int size)
Calling this function before inserting items into an empty UDSEntry may save time and memory.
Definition udsentry.cpp:385
void fastInsert(uint field, const QString &value)
insert field with string value, it will assert if the field is already inserted.
Definition udsentry.cpp:390
QString stringValue(uint field) const
Definition udsentry.cpp:365
long long numberValue(uint field, long long defaultValue=0) const
Definition udsentry.cpp:370
bool isLink() const
Definition udsentry.cpp:380
@ UDS_LOCAL_USER_ID
User ID of the file owner.
Definition udsentry.h:309
@ UDS_CREATION_TIME
The time the file was created. Required time format: seconds since UNIX epoch.
Definition udsentry.h:238
@ UDS_ICON_OVERLAY_NAMES
A comma-separated list of supplementary icon overlays which will be added to the list of overlays cre...
Definition udsentry.h:288
@ UDS_HIDDEN
Treat the file as a hidden file (if set to 1) or as a normal file (if set to 0).
Definition udsentry.h:230
@ UDS_URL
An alternative URL (If different from the caption).
Definition udsentry.h:251
@ UDS_GROUP
Group Name of the file owner Not present on local fs, use UDS_LOCAL_GROUP_ID.
Definition udsentry.h:214
@ UDS_LINK_DEST
Name of the file where the link points to Allows to check for a symlink (don't use S_ISLNK !...
Definition udsentry.h:245
@ UDS_LOCAL_GROUP_ID
Group ID of the file owner.
Definition udsentry.h:312
@ UDS_MIME_TYPE
A MIME type; the KIO worker should set it if it's known.
Definition udsentry.h:253
@ UDS_LOCAL_PATH
A local file path if the KIO worker display files sitting on the local filesystem (but in another hie...
Definition udsentry.h:227
@ UDS_FILE_TYPE
File type, part of the mode returned by stat (for a link, this returns the file type of the pointed i...
Definition udsentry.h:242
@ UDS_DISPLAY_TYPE
User-readable type of file (if not specified, the MIME type's description is used)
Definition udsentry.h:281
@ UDS_MODIFICATION_TIME
The last time the file was modified. Required time format: seconds since UNIX epoch.
Definition udsentry.h:234
@ UDS_COMMENT
A comment which will be displayed as is to the user.
Definition udsentry.h:294
@ UDS_SIZE
Size of the file.
Definition udsentry.h:203
@ UDS_DEVICE_ID
Device number for this file, used to detect hardlinks.
Definition udsentry.h:298
@ UDS_ACCESS_TIME
The last time the file was opened. Required time format: seconds since UNIX epoch.
Definition udsentry.h:236
@ UDS_DISPLAY_NAME
If set, contains the label to display instead of the 'real name' in UDS_NAME.
Definition udsentry.h:272
@ UDS_DEFAULT_ACL_STRING
The default access control list serialized into a single string.
Definition udsentry.h:267
@ UDS_NAME
Filename - as displayed in directory listings etc.
Definition udsentry.h:224
@ UDS_TARGET_URL
This file is a shortcut or mount, pointing to an URL in a different hierarchy.
Definition udsentry.h:276
@ UDS_ICON_NAME
Name of the icon, that should be used for displaying.
Definition udsentry.h:211
@ UDS_EXTRA
Extra data (used only if you specified Columns/ColumnsTypes) NB: you cannot repeat this entry; use UD...
Definition udsentry.h:317
@ UDS_ACL_STRING
The access control list serialized into a single string.
Definition udsentry.h:264
@ UDS_EXTRA_END
Extra data (used only if you specified Columns/ColumnsTypes) NB: you cannot repeat this entry; use UD...
Definition udsentry.h:321
@ UDS_GUESSED_MIME_TYPE
A MIME type to be used for displaying only.
Definition udsentry.h:257
@ UDS_XML_PROPERTIES
XML properties, e.g. for WebDAV.
Definition udsentry.h:259
@ UDS_INODE
Inode number for this file, used to detect hardlinks.
Definition udsentry.h:301
@ UDS_USER
User Name of the file owner Not present on local fs, use UDS_LOCAL_USER_ID.
Definition udsentry.h:208
@ UDS_EXTENDED_ACL
Indicates that the entry has extended ACL entries.
Definition udsentry.h:262
@ UDS_ACCESS
Access permissions (part of the mode returned by stat)
Definition udsentry.h:232
bool contains(uint field) const
check existence of a field
Definition udsentry.cpp:420
UDSEntry & operator=(const UDSEntry &)
Copy assignment.
void replace(uint field, const QString &value)
Replace or insert field with string value.
Definition udsentry.cpp:400
bool isDir() const
Definition udsentry.cpp:375
void clear()
remove all fields
Definition udsentry.cpp:425
~UDSEntry()
Destructor.
@ UDS_STRING
Indicates that the field is a QString.
Definition udsentry.h:189
@ UDS_NUMBER
Indicates that the field is a number (long long)
Definition udsentry.h:191
int count() const
count fields
Definition udsentry.cpp:415
KCALENDARCORE_EXPORT QDataStream & operator>>(QDataStream &in, const KCalendarCore::Alarm::Ptr &)
A namespace for KIO globals.
KIOCORE_EXPORT bool operator!=(const UDSEntry &entry, const UDSEntry &other)
Returns true if the entry does not contain the same data as the other.
Definition udsentry.cpp:489
KIOCORE_EXPORT bool operator==(const UDSEntry &entry, const UDSEntry &other)
Returns true if the entry contains the same data as the other.
Definition udsentry.cpp:463
QDebug & nospace()
void append(QList< T > &&value)
const_reference at(qsizetype i) const const
void reserve(qsizetype size)
void resize(qsizetype size)
qsizetype size() const const
bool isEmpty() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Mon Nov 18 2024 12:16:27 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.