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 
22 using namespace KIO;
23 
24 // BEGIN UDSEntryPrivate
25 /* ---------- UDSEntryPrivate ------------ */
26 
27 class KIO::UDSEntryPrivate : public QSharedData
28 {
29 public:
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 
50 private:
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 
73 void UDSEntryPrivate::reserve(int size)
74 {
75  storage.reserve(size);
76 }
77 
78 void 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 
90 void 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 
103 void 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 
115 void 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 
128 int UDSEntryPrivate::count() const
129 {
130  return storage.size();
131 }
132 
133 QString 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 
144 long 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 
155 QList<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 
165 bool 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 
173 void UDSEntryPrivate::clear()
174 {
175  storage.clear();
176 }
177 
178 void 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 
196 void 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 
238 QString UDSEntryPrivate::nameOfUdsField(uint field)
239 {
240  switch (field) {
241  case UDSEntry::UDS_SIZE:
242  return QStringLiteral("UDS_SIZE");
244  return QStringLiteral("UDS_SIZE_LARGE");
245  case UDSEntry::UDS_USER:
246  return QStringLiteral("UDS_USER");
248  return QStringLiteral("UDS_ICON_NAME");
249  case UDSEntry::UDS_GROUP:
250  return QStringLiteral("UDS_GROUP");
251  case UDSEntry::UDS_NAME:
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");
273  case UDSEntry::UDS_URL:
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");
299  case UDSEntry::UDS_INODE:
300  return QStringLiteral("UDS_INODE");
301  case UDSEntry::UDS_EXTRA:
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 
310 void 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 
331 UDSEntry::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)
337 UDSEntry::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 
359 UDSEntry::UDSEntry(const UDSEntry &) = default;
360 UDSEntry::~UDSEntry() = default;
361 UDSEntry::UDSEntry(UDSEntry &&) = default;
362 UDSEntry &UDSEntry::operator=(const UDSEntry &) = default;
363 UDSEntry &UDSEntry::operator=(UDSEntry &&) = default;
364 
366 {
367  return d->stringValue(field);
368 }
369 
370 long long UDSEntry::numberValue(uint field, long long defaultValue) const
371 {
372  return d->numberValue(field, defaultValue);
373 }
374 
375 bool UDSEntry::isDir() const
376 {
377  return Utils::isDirMask(numberValue(UDS_FILE_TYPE));
378 }
379 
380 bool UDSEntry::isLink() const
381 {
382  return !stringValue(UDS_LINK_DEST).isEmpty();
383 }
384 
385 void UDSEntry::reserve(int size)
386 {
387  d->reserve(size);
388 }
389 
390 void UDSEntry::fastInsert(uint field, const QString &value)
391 {
392  d->insert(field, value);
393 }
394 
395 void UDSEntry::fastInsert(uint field, long long value)
396 {
397  d->insert(field, value);
398 }
399 
400 void UDSEntry::replace(uint field, const QString &value)
401 {
402  d->replace(field, value);
403 }
404 
405 void UDSEntry::replace(uint field, long long value)
406 {
407  d->replace(field, value);
408 }
409 
411 {
412  return d->fields();
413 }
414 
415 int UDSEntry::count() const
416 {
417  return d->count();
418 }
419 
420 bool UDSEntry::contains(uint field) const
421 {
422  return d->contains(field);
423 }
424 
426 {
427  d->clear();
428 }
429 // END UDSEntry
430 
431 KIOCORE_EXPORT QDebug operator<<(QDebug stream, const KIO::UDSEntry &entry)
432 {
433  entry.d->debugUDSEntry(stream);
434  return stream;
435 }
436 
437 KIOCORE_EXPORT QDataStream &operator<<(QDataStream &s, const KIO::UDSEntry &a)
438 {
439  a.d->save(s);
440  return s;
441 }
442 
443 KIOCORE_EXPORT QDataStream &operator>>(QDataStream &s, KIO::UDSEntry &a)
444 {
445  a.d->load(s);
446  return s;
447 }
448 
449 KIOCORE_EXPORT bool operator==(const KIO::UDSEntry &entry, const KIO::UDSEntry &other)
450 {
451  if (entry.count() != other.count()) {
452  return false;
453  }
454 
455  const QList<uint> fields = entry.fields();
456  for (uint field : fields) {
457  if (!other.contains(field)) {
458  return false;
459  }
460 
461  if (field & UDSEntry::UDS_STRING) {
462  if (entry.stringValue(field) != other.stringValue(field)) {
463  return false;
464  }
465  } else {
466  if (entry.numberValue(field) != other.numberValue(field)) {
467  return false;
468  }
469  }
470  }
471 
472  return true;
473 }
474 
475 KIOCORE_EXPORT bool operator!=(const KIO::UDSEntry &entry, const KIO::UDSEntry &other)
476 {
477  return !(entry == other);
478 }
void append(const T &value)
QAction * load(const QObject *recvr, const char *slot, QObject *parent)
int count() const
count fields
Definition: udsentry.cpp:415
@ UDS_DEFAULT_ACL_STRING
The default access control list serialized into a single string.
Definition: udsentry.h:267
KCALENDARCORE_EXPORT QDataStream & operator<<(QDataStream &out, const KCalendarCore::Alarm::Ptr &)
@ 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_LOCAL_USER_ID
User ID of the file owner.
Definition: udsentry.h:309
@ UDS_ACCESS_TIME
The last time the file was opened. Required time format: seconds since UNIX epoch.
Definition: udsentry.h:236
@ 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
QDebug & nospace()
@ UDS_USER
User Name of the file owner Not present on local fs, use UDS_LOCAL_USER_ID.
Definition: udsentry.h:208
bool isDir() const
Definition: udsentry.cpp:375
@ UDS_GUESSED_MIME_TYPE
A MIME type to be used for displaying only.
Definition: udsentry.h:257
@ UDS_TARGET_URL
This file is a shortcut or mount, pointing to an URL in a different hierarchy.
Definition: udsentry.h:276
KCALENDARCORE_EXPORT QDataStream & operator>>(QDataStream &in, const KCalendarCore::Alarm::Ptr &)
@ 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
void reserve(int size)
bool insert(Part *part, qint64 *insertId=nullptr)
@ 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_NAME
Filename - as displayed in directory listings etc.
Definition: udsentry.h:224
@ UDS_NUMBER
Indicates that the field is a number (long long)
Definition: udsentry.h:190
void reserve(int alloc)
QString stringValue(uint field) const
Definition: udsentry.cpp:365
@ UDS_INODE
Inode number for this file, used to detect hardlinks.
Definition: udsentry.h:301
@ UDS_ICON_NAME
Name of the icon, that should be used for displaying.
Definition: udsentry.h:211
bool operator==(const Qt3DRender::QGraphicsApiFilter &reference, const Qt3DRender::QGraphicsApiFilter &sample)
@ UDS_LOCAL_GROUP_ID
Group ID of the file owner.
Definition: udsentry.h:312
@ UDS_URL
An alternative URL (If different from the caption).
Definition: udsentry.h:251
bool isEmpty() const const
bool operator!=(const Qt3DRender::QGraphicsApiFilter &reference, const Qt3DRender::QGraphicsApiFilter &sample)
@ UDS_SIZE
Size of the file.
Definition: udsentry.h:203
QAction * replace(const QObject *recvr, const char *slot, QObject *parent)
void reserve(int size)
Calling this function before inserting items into an empty UDSEntry may save time and memory.
Definition: udsentry.cpp:385
@ UDS_EXTRA
Extra data (used only if you specified Columns/ColumnsTypes) NB: you cannot repeat this entry; use UD...
Definition: udsentry.h:317
~UDSEntry()
Destructor.
void clear()
remove all fields
Definition: udsentry.cpp:425
@ UDS_GROUP
Group Name of the file owner Not present on local fs, use UDS_LOCAL_GROUP_ID.
Definition: udsentry.h:214
bool isLink() const
Definition: udsentry.cpp:380
QAction * clear(const QObject *recvr, const char *slot, QObject *parent)
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
long long numberValue(uint field, long long defaultValue=0) const
Definition: udsentry.cpp:370
@ 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_MODIFICATION_TIME
The last time the file was modified. Required time format: seconds since UNIX epoch.
Definition: udsentry.h:234
void replace(uint field, const QString &value)
Replace or insert field with string value.
Definition: udsentry.cpp:400
@ UDS_EXTENDED_ACL
Indicates that the entry has extended ACL entries.
Definition: udsentry.h:262
@ UDS_DISPLAY_TYPE
User-readable type of file (if not specified, the MIME type's description is used)
Definition: udsentry.h:281
A namespace for KIO globals.
@ UDS_ACL_STRING
The access control list serialized into a single string.
Definition: udsentry.h:264
@ UDS_STRING
Indicates that the field is a QString.
Definition: udsentry.h:188
@ UDS_ACCESS
Access permissions (part of the mode returned by stat)
Definition: udsentry.h:232
@ UDS_DISPLAY_NAME
If set, contains the label to display instead of the 'real name' in UDS_NAME.
Definition: udsentry.h:272
@ UDS_DEVICE_ID
Device number for this file, used to detect hardlinks.
Definition: udsentry.h:298
UDSEntry & operator=(const UDSEntry &)
Copy assignment.
QList< uint > fields() const
A vector of fields being present for the current entry.
Definition: udsentry.cpp:410
@ UDS_MIME_TYPE
A MIME type; the KIO worker should set it if it's known.
Definition: udsentry.h:253
bool contains(uint field) const
check existence of a field
Definition: udsentry.cpp:420
@ 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_XML_PROPERTIES
XML properties, e.g. for WebDAV.
Definition: udsentry.h:259
@ UDS_COMMENT
A comment which will be displayed as is to the user.
Definition: udsentry.h:294
QAction * save(const QObject *recvr, const char *slot, QObject *parent)
@ UDS_CREATION_TIME
The time the file was created. Required time format: seconds since UNIX epoch.
Definition: udsentry.h:238
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Thu Feb 15 2024 03:51:27 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.