KIO

udsentry.cpp
1 /*
2  This file is part of the KDE project
3  SPDX-FileCopyrightText: 2000-2005 David Faure <[email protected]>
4  SPDX-FileCopyrightText: 2007 Norbert Frese <[email protected]>
5  SPDX-FileCopyrightText: 2007 Thiago Macieira <[email protected]>
6  SPDX-FileCopyrightText: 2013-2014 Frank Reininghaus <[email protected]>
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 <QString>
18 #include <QVector>
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 #if KIOCORE_BUILD_DEPRECATED_SINCE(5, 8)
39  QList<uint> listFields() const;
40 #endif
41  QVector<uint> fields() const;
42  bool contains(uint udsField) const;
43  void clear();
44  void save(QDataStream &s) const;
45  void load(QDataStream &s);
46  void debugUDSEntry(QDebug &stream) const;
47  /**
48  * @param field numeric UDS field id
49  * @return the name of the field
50  */
51  static QString nameOfUdsField(uint field);
52 
53 private:
54  struct Field {
55  inline Field()
56  {
57  }
58  inline Field(const uint index, const QString &value)
59  : m_str(value)
60  , m_index(index)
61  {
62  }
63  inline Field(const uint index, long long value = 0)
64  : m_long(value)
65  , m_index(index)
66  {
67  }
68 
69  QString m_str;
70  long long m_long = LLONG_MIN;
71  uint m_index = 0;
72  };
73  std::vector<Field> storage;
74 };
75 
76 void UDSEntryPrivate::reserve(int size)
77 {
78  storage.reserve(size);
79 }
80 
81 void UDSEntryPrivate::insert(uint udsField, const QString &value)
82 {
83  Q_ASSERT(udsField & KIO::UDSEntry::UDS_STRING);
84  Q_ASSERT(std::find_if(storage.cbegin(),
85  storage.cend(),
86  [udsField](const Field &entry) {
87  return entry.m_index == udsField;
88  })
89  == storage.cend());
90  storage.emplace_back(udsField, value);
91 }
92 
93 void UDSEntryPrivate::replace(uint udsField, const QString &value)
94 {
95  Q_ASSERT(udsField & KIO::UDSEntry::UDS_STRING);
96  auto it = std::find_if(storage.begin(), storage.end(), [udsField](const Field &entry) {
97  return entry.m_index == udsField;
98  });
99  if (it != storage.end()) {
100  it->m_str = value;
101  return;
102  }
103  storage.emplace_back(udsField, value);
104 }
105 
106 void UDSEntryPrivate::insert(uint udsField, long long value)
107 {
108  Q_ASSERT(udsField & KIO::UDSEntry::UDS_NUMBER);
109  Q_ASSERT(std::find_if(storage.cbegin(),
110  storage.cend(),
111  [udsField](const Field &entry) {
112  return entry.m_index == udsField;
113  })
114  == storage.cend());
115  storage.emplace_back(udsField, value);
116 }
117 
118 void UDSEntryPrivate::replace(uint udsField, long long value)
119 {
120  Q_ASSERT(udsField & KIO::UDSEntry::UDS_NUMBER);
121  auto it = std::find_if(storage.begin(), storage.end(), [udsField](const Field &entry) {
122  return entry.m_index == udsField;
123  });
124  if (it != storage.end()) {
125  it->m_long = value;
126  return;
127  }
128  storage.emplace_back(udsField, value);
129 }
130 
131 int UDSEntryPrivate::count() const
132 {
133  return storage.size();
134 }
135 
136 QString UDSEntryPrivate::stringValue(uint udsField) const
137 {
138  auto it = std::find_if(storage.cbegin(), storage.cend(), [udsField](const Field &entry) {
139  return entry.m_index == udsField;
140  });
141  if (it != storage.cend()) {
142  return it->m_str;
143  }
144  return QString();
145 }
146 
147 long long UDSEntryPrivate::numberValue(uint udsField, long long defaultValue) const
148 {
149  auto it = std::find_if(storage.cbegin(), storage.cend(), [udsField](const Field &entry) {
150  return entry.m_index == udsField;
151  });
152  if (it != storage.cend()) {
153  return it->m_long;
154  }
155  return defaultValue;
156 }
157 
158 #if KIOCORE_BUILD_DEPRECATED_SINCE(5, 8)
159 QList<uint> UDSEntryPrivate::listFields() const
160 {
161  QList<uint> res;
162  res.reserve(storage.size());
163  for (const Field &field : storage) {
164  res.append(field.m_index);
165  }
166  return res;
167 }
168 #endif
169 
170 QVector<uint> UDSEntryPrivate::fields() const
171 {
172  QVector<uint> res;
173  res.reserve(storage.size());
174  for (const Field &field : storage) {
175  res.append(field.m_index);
176  }
177  return res;
178 }
179 
180 bool UDSEntryPrivate::contains(uint udsField) const
181 {
182  auto it = std::find_if(storage.cbegin(), storage.cend(), [udsField](const Field &entry) {
183  return entry.m_index == udsField;
184  });
185  return (it != storage.cend());
186 }
187 
188 void UDSEntryPrivate::clear()
189 {
190  storage.clear();
191 }
192 
193 void UDSEntryPrivate::save(QDataStream &s) const
194 {
195  s << static_cast<quint32>(storage.size());
196 
197  for (const Field &field : storage) {
198  uint uds = field.m_index;
199  s << uds;
200 
201  if (uds & KIO::UDSEntry::UDS_STRING) {
202  s << field.m_str;
203  } else if (uds & KIO::UDSEntry::UDS_NUMBER) {
204  s << field.m_long;
205  } else {
206  Q_ASSERT_X(false, "KIO::UDSEntry", "Found a field with an invalid type");
207  }
208  }
209 }
210 
211 void UDSEntryPrivate::load(QDataStream &s)
212 {
213  clear();
214 
215  quint32 size;
216  s >> size;
217  reserve(size);
218 
219  // We cache the loaded strings. Some of them, like, e.g., the user,
220  // will often be the same for many entries in a row. Caching them
221  // permits to use implicit sharing to save memory.
222  thread_local QVector<QString> cachedStrings;
223  if (quint32(cachedStrings.size()) < size) {
224  cachedStrings.resize(size);
225  }
226 
227  for (quint32 i = 0; i < size; ++i) {
228  quint32 uds;
229  s >> uds;
230 
231  if (uds & KIO::UDSEntry::UDS_STRING) {
232  // If the QString is the same like the one we read for the
233  // previous UDSEntry at the i-th position, use an implicitly
234  // shared copy of the same QString to save memory.
235  QString buffer;
236  s >> buffer;
237 
238  if (buffer != cachedStrings.at(i)) {
239  cachedStrings[i] = buffer;
240  }
241 
242  insert(uds, cachedStrings.at(i));
243  } else if (uds & KIO::UDSEntry::UDS_NUMBER) {
244  long long value;
245  s >> value;
246  insert(uds, value);
247  } else {
248  Q_ASSERT_X(false, "KIO::UDSEntry", "Found a field with an invalid type");
249  }
250  }
251 }
252 
253 QString UDSEntryPrivate::nameOfUdsField(uint field)
254 {
255  switch (field) {
256  case UDSEntry::UDS_SIZE:
257  return QStringLiteral("UDS_SIZE");
259  return QStringLiteral("UDS_SIZE_LARGE");
260  case UDSEntry::UDS_USER:
261  return QStringLiteral("UDS_USER");
263  return QStringLiteral("UDS_ICON_NAME");
264  case UDSEntry::UDS_GROUP:
265  return QStringLiteral("UDS_GROUP");
266  case UDSEntry::UDS_NAME:
267  return QStringLiteral("UDS_NAME");
269  return QStringLiteral("UDS_LOCAL_PATH");
271  return QStringLiteral("UDS_HIDDEN");
273  return QStringLiteral("UDS_ACCESS");
275  return QStringLiteral("UDS_MODIFICATION_TIME");
277  return QStringLiteral("UDS_ACCESS_TIME");
279  return QStringLiteral("UDS_CREATION_TIME");
281  return QStringLiteral("UDS_FILE_TYPE");
283  return QStringLiteral("UDS_LINK_DEST");
284  case UDSEntry::UDS_URL:
285  return QStringLiteral("UDS_URL");
287  return QStringLiteral("UDS_MIME_TYPE");
289  return QStringLiteral("UDS_GUESSED_MIME_TYPE");
291  return QStringLiteral("UDS_XML_PROPERTIES");
293  return QStringLiteral("UDS_EXTENDED_ACL");
295  return QStringLiteral("UDS_ACL_STRING");
297  return QStringLiteral("UDS_DEFAULT_ACL_STRING");
299  return QStringLiteral("UDS_DISPLAY_NAME");
301  return QStringLiteral("UDS_TARGET_URL");
303  return QStringLiteral("UDS_DISPLAY_TYPE");
305  return QStringLiteral("UDS_ICON_OVERLAY_NAMES");
307  return QStringLiteral("UDS_COMMENT");
309  return QStringLiteral("UDS_DEVICE_ID");
310  case UDSEntry::UDS_INODE:
311  return QStringLiteral("UDS_INODE");
312  case UDSEntry::UDS_EXTRA:
313  return QStringLiteral("UDS_EXTRA");
315  return QStringLiteral("UDS_EXTRA_END");
316  default:
317  return QStringLiteral("Unknown uds field %1").arg(field);
318  }
319 }
320 
321 void UDSEntryPrivate::debugUDSEntry(QDebug &stream) const
322 {
323  QDebugStateSaver saver(stream);
324  stream.nospace() << "[";
325  for (const Field &field : storage) {
326  stream << " " << nameOfUdsField(field.m_index) << "=";
327  if (field.m_index & KIO::UDSEntry::UDS_STRING) {
328  stream << field.m_str;
329  } else if (field.m_index & KIO::UDSEntry::UDS_NUMBER) {
330  stream << field.m_long;
331  } else {
332  Q_ASSERT_X(false, "KIO::UDSEntry", "Found a field with an invalid type");
333  }
334  }
335  stream << " ]";
336 }
337 // END UDSEntryPrivate
338 
339 // BEGIN UDSEntry
340 /* ---------- UDSEntry ------------ */
341 
342 UDSEntry::UDSEntry()
343  : d(new UDSEntryPrivate())
344 {
345 }
346 
347 // 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)
348 UDSEntry::UDSEntry(const QT_STATBUF &buff, const QString &name)
349  : d(new UDSEntryPrivate())
350 {
351 #ifndef Q_OS_WIN
352  d->reserve(10);
353 #else
354  d->reserve(8);
355 #endif
356  d->insert(UDS_NAME, name);
357  d->insert(UDS_SIZE, buff.st_size);
358  d->insert(UDS_DEVICE_ID, buff.st_dev);
359  d->insert(UDS_INODE, buff.st_ino);
360  d->insert(UDS_FILE_TYPE, buff.st_mode & QT_STAT_MASK); // extract file type
361  d->insert(UDS_ACCESS, buff.st_mode & 07777); // extract permissions
362  d->insert(UDS_MODIFICATION_TIME, buff.st_mtime);
363  d->insert(UDS_ACCESS_TIME, buff.st_atime);
364 #ifndef Q_OS_WIN
365  d->insert(UDS_USER, KUser(buff.st_uid).loginName());
366  d->insert(UDS_GROUP, KUserGroup(buff.st_gid).name());
367 #endif
368 }
369 
370 UDSEntry::UDSEntry(const UDSEntry &) = default;
371 UDSEntry::~UDSEntry() = default;
372 UDSEntry::UDSEntry(UDSEntry &&) = default;
373 UDSEntry &UDSEntry::operator=(const UDSEntry &) = default;
374 UDSEntry &UDSEntry::operator=(UDSEntry &&) = default;
375 
377 {
378  return d->stringValue(field);
379 }
380 
381 long long UDSEntry::numberValue(uint field, long long defaultValue) const
382 {
383  return d->numberValue(field, defaultValue);
384 }
385 
386 bool UDSEntry::isDir() const
387 {
388  return Utils::isDirMask(numberValue(UDS_FILE_TYPE));
389 }
390 
391 bool UDSEntry::isLink() const
392 {
393  return !stringValue(UDS_LINK_DEST).isEmpty();
394 }
395 
396 void UDSEntry::reserve(int size)
397 {
398  d->reserve(size);
399 }
400 
401 void UDSEntry::fastInsert(uint field, const QString &value)
402 {
403  d->insert(field, value);
404 }
405 
406 void UDSEntry::fastInsert(uint field, long long value)
407 {
408  d->insert(field, value);
409 }
410 
411 #if KIOCORE_BUILD_DEPRECATED_SINCE(5, 48)
412 void UDSEntry::insert(uint field, const QString &value)
413 {
414  d->replace(field, value);
415 }
416 #endif
417 
418 #if KIOCORE_BUILD_DEPRECATED_SINCE(5, 48)
419 void UDSEntry::insert(uint field, long long value)
420 {
421  d->replace(field, value);
422 }
423 #endif
424 
425 void UDSEntry::replace(uint field, const QString &value)
426 {
427  d->replace(field, value);
428 }
429 
430 void UDSEntry::replace(uint field, long long value)
431 {
432  d->replace(field, value);
433 }
434 
435 #if KIOCORE_BUILD_DEPRECATED_SINCE(5, 8)
437 {
438  return d->listFields();
439 }
440 #endif
441 
443 {
444  return d->fields();
445 }
446 
447 int UDSEntry::count() const
448 {
449  return d->count();
450 }
451 
452 bool UDSEntry::contains(uint field) const
453 {
454  return d->contains(field);
455 }
456 
458 {
459  d->clear();
460 }
461 // END UDSEntry
462 
463 KIOCORE_EXPORT QDebug operator<<(QDebug stream, const KIO::UDSEntry &entry)
464 {
465  entry.d->debugUDSEntry(stream);
466  return stream;
467 }
468 
469 KIOCORE_EXPORT QDataStream &operator<<(QDataStream &s, const KIO::UDSEntry &a)
470 {
471  a.d->save(s);
472  return s;
473 }
474 
475 KIOCORE_EXPORT QDataStream &operator>>(QDataStream &s, KIO::UDSEntry &a)
476 {
477  a.d->load(s);
478  return s;
479 }
480 
481 KIOCORE_EXPORT bool operator==(const KIO::UDSEntry &entry, const KIO::UDSEntry &other)
482 {
483  if (entry.count() != other.count()) {
484  return false;
485  }
486 
487  const QVector<uint> fields = entry.fields();
488  for (uint field : fields) {
489  if (!other.contains(field)) {
490  return false;
491  }
492 
493  if (field & UDSEntry::UDS_STRING) {
494  if (entry.stringValue(field) != other.stringValue(field)) {
495  return false;
496  }
497  } else {
498  if (entry.numberValue(field) != other.numberValue(field)) {
499  return false;
500  }
501  }
502  }
503 
504  return true;
505 }
506 
507 KIOCORE_EXPORT bool operator!=(const KIO::UDSEntry &entry, const KIO::UDSEntry &other)
508 {
509  return !(entry == other);
510 }
void append(const T &value)
int count() const
count fields
Definition: udsentry.cpp:447
@ UDS_DEFAULT_ACL_STRING
The default access control list serialized into a single string.
Definition: udsentry.h:292
KCALENDARCORE_EXPORT QDataStream & operator<<(QDataStream &out, const KCalendarCore::Alarm::Ptr &)
@ UDS_ICON_OVERLAY_NAMES
25 was used by the now removed UDS_NEPOMUK_URI
Definition: udsentry.h:315
@ UDS_ACCESS_TIME
The last time the file was opened. Required time format: seconds since UNIX epoch.
Definition: udsentry.h:261
@ 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:255
QDebug & nospace()
@ UDS_USER
User ID of the file owner.
Definition: udsentry.h:234
bool isDir() const
Definition: udsentry.cpp:386
void append(const T &value)
@ UDS_GUESSED_MIME_TYPE
A MIME type to be used for displaying only.
Definition: udsentry.h:282
@ UDS_TARGET_URL
This file is a shortcut or mount, pointing to an URL in a different hierarchy.
Definition: udsentry.h:301
QVector< uint > fields() const
A vector of fields being present for the current entry.
Definition: udsentry.cpp:442
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:270
QAction * load(const QObject *recvr, const char *slot, QObject *parent)
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:267
@ UDS_NAME
Filename - as displayed in directory listings etc.
Definition: udsentry.h:249
void reserve(int alloc)
QString stringValue(uint field) const
Definition: udsentry.cpp:376
void insert(uint field, const QString &value)
insert field with string value
Definition: udsentry.cpp:412
@ UDS_INODE
Inode number for this file, used to detect hardlinks.
Definition: udsentry.h:330
@ UDS_ICON_NAME
Name of the icon, that should be used for displaying.
Definition: udsentry.h:237
QList< uint > listFields() const
List all fields.
Definition: udsentry.cpp:436
bool operator==(const Qt3DRender::QGraphicsApiFilter &reference, const Qt3DRender::QGraphicsApiFilter &sample)
@ UDS_URL
An alternative URL (If different from the caption).
Definition: udsentry.h:276
bool isEmpty() const const
bool operator!=(const Qt3DRender::QGraphicsApiFilter &reference, const Qt3DRender::QGraphicsApiFilter &sample)
@ UDS_SIZE
Size of the file.
Definition: udsentry.h:230
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:396
QString name() const
void resize(int size)
@ UDS_EXTRA
Extra data (used only if you specified Columns/ColumnsTypes) NB: you cannot repeat this entry; use UD...
Definition: udsentry.h:339
~UDSEntry()
Destructor.
QString loginName() const
void reserve(int size)
void clear()
remove all fields
Definition: udsentry.cpp:457
@ UDS_GROUP
Group ID of the file owner.
Definition: udsentry.h:239
bool isLink() const
Definition: udsentry.cpp:391
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:401
long long numberValue(uint field, long long defaultValue=0) const
Definition: udsentry.cpp:381
@ 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:252
@ UDS_MODIFICATION_TIME
The last time the file was modified. Required time format: seconds since UNIX epoch.
Definition: udsentry.h:259
void replace(uint field, const QString &value)
Replace or insert field with string value.
Definition: udsentry.cpp:425
@ UDS_EXTENDED_ACL
Indicates that the entry has extended ACL entries.
Definition: udsentry.h:287
@ UDS_DISPLAY_TYPE
User-readable type of file (if not specified, the MIME type's description is used)
Definition: udsentry.h:306
A namespace for KIO globals.
@ UDS_ACL_STRING
The access control list serialized into a single string.
Definition: udsentry.h:289
@ UDS_STRING
Indicates that the field is a QString.
Definition: udsentry.h:221
@ UDS_ACCESS
Access permissions (part of the mode returned by stat)
Definition: udsentry.h:257
@ UDS_DISPLAY_NAME
If set, contains the label to display instead of the 'real name' in UDS_NAME.
Definition: udsentry.h:297
@ UDS_DEVICE_ID
Device number for this file, used to detect hardlinks.
Definition: udsentry.h:327
UDSEntry & operator=(const UDSEntry &)
Copy assignment.
@ UDS_NUMBER
Indicates that the field is a number (long long)
Definition: udsentry.h:223
@ UDS_MIME_TYPE
A MIME type; the KIO worker should set it if it's known.
Definition: udsentry.h:278
bool contains(uint field) const
check existence of a field
Definition: udsentry.cpp:452
@ UDS_EXTRA_END
Extra data (used only if you specified Columns/ColumnsTypes) NB: you cannot repeat this entry; use UD...
Definition: udsentry.h:343
@ UDS_XML_PROPERTIES
XML properties, e.g. for WebDAV.
Definition: udsentry.h:284
@ UDS_COMMENT
27 was used by the now removed UDS_NEPOMUK_QUERY
Definition: udsentry.h:323
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:263
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Thu Mar 23 2023 03:59:43 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.