1 /*
2     This file is part of the KDE libraries
3     SPDX-FileCopyrightText: 2006, 2007 Thomas Braxton <kde.braxton@gmail.com>
4     SPDX-FileCopyrightText: 1999 Preston Brown <pbrown@kde.org>
5     SPDX-FileCopyrightText: 1997 Matthias Kalle Dalheimer <kalle@kde.org>
6 
7     SPDX-License-Identifier: LGPL-2.0-or-later
8 */
9 
10 #include "kconfiggroup.h"
11 #include "kconfiggroup_p.h"
12 
13 #include "kconfig.h"
14 #include "kconfig_core_log_settings.h"
15 #include "kconfig_p.h"
16 #include "kconfigdata_p.h"
17 #include "ksharedconfig.h"
18 
19 #include <QDate>
20 #include <QDir>
21 #include <QFile>
22 #include <QPoint>
23 #include <QRect>
24 #include <QSharedData>
25 #include <QString>
26 #include <QTextStream>
27 #include <QUrl>
28 
29 #include <algorithm>
30 #include <array>
31 #include <math.h>
32 #include <stdlib.h>
33 
34 class KConfigGroupPrivate : public QSharedData
35 {
36 public:
KConfigGroupPrivate(KConfig * owner,bool isImmutable,bool isConst,const QByteArray & name)37     KConfigGroupPrivate(KConfig *owner, bool isImmutable, bool isConst, const QByteArray &name)
38         : mOwner(owner)
39         , mName(name)
40         , bImmutable(isImmutable)
41         , bConst(isConst)
42     {
43     }
44 
KConfigGroupPrivate(const KSharedConfigPtr & owner,const QByteArray & name)45     KConfigGroupPrivate(const KSharedConfigPtr &owner, const QByteArray &name)
46         : sOwner(owner)
47         , mOwner(sOwner.data())
48         , mName(name)
49         , bImmutable(name.isEmpty() ? owner->isImmutable() : owner->isGroupImmutable(name))
50         , bConst(false)
51     {
52     }
53 
KConfigGroupPrivate(KConfigGroup * parent,bool isImmutable,bool isConst,const QByteArray & name)54     KConfigGroupPrivate(KConfigGroup *parent, bool isImmutable, bool isConst, const QByteArray &name)
55         : sOwner(parent->d->sOwner)
56         , mOwner(parent->d->mOwner)
57         , mName(name)
58         , bImmutable(isImmutable)
59         , bConst(isConst)
60     {
61         if (!parent->d->mName.isEmpty()) {
62             mParent = parent->d;
63         }
64     }
65 
KConfigGroupPrivate(const KConfigGroupPrivate * other,bool isImmutable,const QByteArray & name)66     KConfigGroupPrivate(const KConfigGroupPrivate *other, bool isImmutable, const QByteArray &name)
67         : sOwner(other->sOwner)
68         , mOwner(other->mOwner)
69         , mName(name)
70         , bImmutable(isImmutable)
71         , bConst(other->bConst)
72     {
73         if (!other->mName.isEmpty()) {
74             mParent = const_cast<KConfigGroupPrivate *>(other);
75         }
76     }
77 
78     KSharedConfig::Ptr sOwner;
79     KConfig *mOwner;
80     QExplicitlySharedDataPointer<KConfigGroupPrivate> mParent;
81     QByteArray mName;
82 
83     /* bitfield */
84     const bool bImmutable : 1; // is this group immutable?
85     const bool bConst : 1; // is this group read-only?
86 
fullName() const87     QByteArray fullName() const
88     {
89         if (!mParent) {
90             return name();
91         }
92         return mParent->fullName(mName);
93     }
94 
name() const95     QByteArray name() const
96     {
97         if (mName.isEmpty()) {
98             return QByteArrayLiteral("<default>");
99         }
100         return mName;
101     }
102 
fullName(const QByteArray & aGroup) const103     QByteArray fullName(const QByteArray &aGroup) const
104     {
105         if (mName.isEmpty()) {
106             return aGroup;
107         }
108         return fullName() + '\x1d' + aGroup;
109     }
110 
create(KConfigBase * master,const QByteArray & name,bool isImmutable,bool isConst)111     static QExplicitlySharedDataPointer<KConfigGroupPrivate> create(KConfigBase *master, const QByteArray &name, bool isImmutable, bool isConst)
112     {
113         QExplicitlySharedDataPointer<KConfigGroupPrivate> data;
114         if (dynamic_cast<KConfigGroup *>(master)) {
115             data = new KConfigGroupPrivate(static_cast<KConfigGroup *>(master), isImmutable, isConst, name);
116         } else {
117             data = new KConfigGroupPrivate(dynamic_cast<KConfig *>(master), isImmutable, isConst, name);
118         }
119         return data;
120     }
121 
122     static QByteArray serializeList(const QList<QByteArray> &list);
123     static QStringList deserializeList(const QString &data);
124 };
125 
serializeList(const QList<QByteArray> & list)126 QByteArray KConfigGroupPrivate::serializeList(const QList<QByteArray> &list)
127 {
128     QByteArray value;
129 
130     if (!list.isEmpty()) {
131         auto it = list.cbegin();
132         const auto end = list.cend();
133 
134         value = QByteArray(*it).replace('\\', QByteArrayLiteral("\\\\")).replace(',', QByteArrayLiteral("\\,"));
135 
136         while (++it != end) {
137             // In the loop, so it is not done when there is only one element.
138             // Doing it repeatedly is a pretty cheap operation.
139             value.reserve(4096);
140 
141             value += ',';
142             value += QByteArray(*it).replace('\\', QByteArrayLiteral("\\\\")).replace(',', QByteArrayLiteral("\\,"));
143         }
144 
145         // To be able to distinguish an empty list from a list with one empty element.
146         if (value.isEmpty()) {
147             value = QByteArrayLiteral("\\0");
148         }
149     }
150 
151     return value;
152 }
153 
deserializeList(const QString & data)154 QStringList KConfigGroupPrivate::deserializeList(const QString &data)
155 {
156     if (data.isEmpty()) {
157         return QStringList();
158     }
159     if (data == QLatin1String("\\0")) {
160         return QStringList(QString());
161     }
162     QStringList value;
163     QString val;
164     val.reserve(data.size());
165     bool quoted = false;
166     for (int p = 0; p < data.length(); p++) {
167         if (quoted) {
168             val += data[p];
169             quoted = false;
170         } else if (data[p].unicode() == '\\') {
171             quoted = true;
172         } else if (data[p].unicode() == ',') {
173             val.squeeze(); // release any unused memory
174             value.append(val);
175             val.clear();
176             val.reserve(data.size() - p);
177         } else {
178             val += data[p];
179         }
180     }
181     value.append(val);
182     return value;
183 }
184 
asIntList(const QByteArray & string)185 static QVector<int> asIntList(const QByteArray &string)
186 {
187     const auto &splitString = string.split(',');
188 
189     QVector<int> list;
190     list.reserve(splitString.count());
191     for (const QByteArray &s : splitString) {
192         list << s.toInt();
193     }
194     return list;
195 }
196 
asRealList(const QByteArray & string)197 static QVector<qreal> asRealList(const QByteArray &string)
198 {
199     const auto &splitString = string.split(',');
200 
201     QVector<qreal> list;
202     list.reserve(splitString.count());
203     for (const QByteArray &s : splitString) {
204         list << s.toDouble();
205     }
206     return list;
207 }
208 
errString(const char * pKey,const QByteArray & value,const QVariant & aDefault)209 static QString errString(const char *pKey, const QByteArray &value, const QVariant &aDefault)
210 {
211     return QStringLiteral("\"%1\" - conversion of \"%3\" to %2 failed")
212         .arg(QString::fromLatin1(pKey), QString::fromLatin1(QVariant::typeToName(aDefault.type())), QString::fromLatin1(value));
213 }
214 
formatError(int expected,int got)215 static QString formatError(int expected, int got)
216 {
217     return QStringLiteral(" (wrong format: expected %1 items, got %2)").arg(expected).arg(got);
218 }
219 
convertToQVariant(const char * pKey,const QByteArray & value,const QVariant & aDefault)220 QVariant KConfigGroup::convertToQVariant(const char *pKey, const QByteArray &value, const QVariant &aDefault)
221 {
222     // if a type handler is added here you must add a QVConversions definition
223     // to conversioncheck.h, or ConversionCheck::to_QVariant will not allow
224     // readEntry<T> to convert to QVariant.
225     switch (static_cast<QMetaType::Type>(aDefault.type())) {
226     case QMetaType::UnknownType:
227         return QVariant();
228     case QMetaType::QString:
229         // this should return the raw string not the dollar expanded string.
230         // imho if processed string is wanted should call
231         // readEntry(key, QString) not readEntry(key, QVariant)
232         return QString::fromUtf8(value);
233     case QMetaType::QVariantList:
234     case QMetaType::QStringList:
235         return KConfigGroupPrivate::deserializeList(QString::fromUtf8(value));
236     case QMetaType::QByteArray:
237         return value;
238     case QMetaType::Bool: {
239         static const std::array<const char *, 4> negatives = {"false", "no", "off", "0"};
240 
241         return std::all_of(negatives.begin(), negatives.end(), [value](const char *negativeString) {
242             return value.compare(negativeString, Qt::CaseInsensitive) != 0;
243         });
244     }
245     case QMetaType::Double:
246     case QMetaType::Float:
247     case QMetaType::Int:
248     case QMetaType::UInt:
249     case QMetaType::LongLong:
250     case QMetaType::ULongLong: {
251         QVariant tmp = value;
252         if (!tmp.convert(aDefault.type())) {
253             tmp = aDefault;
254         }
255         return tmp;
256     }
257     case QMetaType::QPoint: {
258         const auto list = asIntList(value);
259 
260         if (list.count() != 2) {
261             qCWarning(KCONFIG_CORE_LOG) << errString(pKey, value, aDefault) << formatError(2, list.count());
262             return aDefault;
263         }
264         return QPoint(list.at(0), list.at(1));
265     }
266     case QMetaType::QPointF: {
267         const auto list = asRealList(value);
268 
269         if (list.count() != 2) {
270             qCWarning(KCONFIG_CORE_LOG) << errString(pKey, value, aDefault) << formatError(2, list.count());
271             return aDefault;
272         }
273         return QPointF(list.at(0), list.at(1));
274     }
275     case QMetaType::QRect: {
276         const auto list = asIntList(value);
277 
278         if (list.count() != 4) {
279             qCWarning(KCONFIG_CORE_LOG) << errString(pKey, value, aDefault) << formatError(4, list.count());
280             return aDefault;
281         }
282         const QRect rect(list.at(0), list.at(1), list.at(2), list.at(3));
283         if (!rect.isValid()) {
284             qCWarning(KCONFIG_CORE_LOG) << errString(pKey, value, aDefault);
285             return aDefault;
286         }
287         return rect;
288     }
289     case QMetaType::QRectF: {
290         const auto list = asRealList(value);
291 
292         if (list.count() != 4) {
293             qCWarning(KCONFIG_CORE_LOG) << errString(pKey, value, aDefault) << formatError(4, list.count());
294             return aDefault;
295         }
296         const QRectF rect(list.at(0), list.at(1), list.at(2), list.at(3));
297         if (!rect.isValid()) {
298             qCWarning(KCONFIG_CORE_LOG) << errString(pKey, value, aDefault);
299             return aDefault;
300         }
301         return rect;
302     }
303     case QMetaType::QSize: {
304         const auto list = asIntList(value);
305 
306         if (list.count() != 2) {
307             qCWarning(KCONFIG_CORE_LOG) << errString(pKey, value, aDefault) << formatError(2, list.count());
308             return aDefault;
309         }
310         const QSize size(list.at(0), list.at(1));
311         if (!size.isValid()) {
312             qCWarning(KCONFIG_CORE_LOG) << errString(pKey, value, aDefault);
313             return aDefault;
314         }
315         return size;
316     }
317     case QMetaType::QSizeF: {
318         const auto list = asRealList(value);
319 
320         if (list.count() != 2) {
321             qCWarning(KCONFIG_CORE_LOG) << errString(pKey, value, aDefault) << formatError(2, list.count());
322             return aDefault;
323         }
324         const QSizeF size(list.at(0), list.at(1));
325         if (!size.isValid()) {
326             qCWarning(KCONFIG_CORE_LOG) << errString(pKey, value, aDefault);
327             return aDefault;
328         }
329         return size;
330     }
331     case QMetaType::QDateTime: {
332         const auto list = asRealList(value);
333         if (list.count() < 6) {
334             qCWarning(KCONFIG_CORE_LOG) << errString(pKey, value, aDefault) << formatError(6, list.count());
335             return aDefault;
336         }
337         const QDate date(list.at(0), list.at(1), list.at(2));
338         const qreal totalSeconds = list.at(5);
339         qreal seconds;
340         const qreal fractional = modf(totalSeconds, &seconds);
341         const qreal milliseconds = round(fractional * 1000.0);
342         const QTime time(list.at(3), list.at(4), seconds, milliseconds);
343         const QDateTime dt(date, time);
344         if (!dt.isValid()) {
345             qCWarning(KCONFIG_CORE_LOG) << errString(pKey, value, aDefault);
346             return aDefault;
347         }
348         return dt;
349     }
350     case QMetaType::QDate: {
351         auto list = asIntList(value);
352         if (list.count() == 6) {
353             list = list.mid(0, 3); // don't break config files that stored QDate as QDateTime
354         }
355         if (list.count() != 3) {
356             qCWarning(KCONFIG_CORE_LOG) << errString(pKey, value, aDefault) << formatError(3, list.count());
357             return aDefault;
358         }
359         const QDate date(list.at(0), list.at(1), list.at(2));
360         if (!date.isValid()) {
361             qCWarning(KCONFIG_CORE_LOG) << errString(pKey, value, aDefault);
362             return aDefault;
363         }
364         return date;
365     }
366     case QMetaType::QColor:
367     case QMetaType::QFont:
368         qCWarning(KCONFIG_CORE_LOG) << "KConfigGroup::readEntry was passed GUI type '" << aDefault.typeName()
369                                     << "' but KConfigGui isn't linked! If it is linked to your program, "
370                                        "this is a platform bug. Please inform the KDE developers";
371         break;
372     case QMetaType::QUrl:
373         return QUrl(QString::fromUtf8(value));
374 
375     default:
376         break;
377     }
378 
379     qCWarning(KCONFIG_CORE_LOG) << "unhandled type " << aDefault.typeName();
380     return QVariant();
381 }
382 
383 #ifdef Q_OS_WIN
384 #include <QDir>
385 #endif
386 
cleanHomeDirPath(QString & path,const QString & homeDir)387 static bool cleanHomeDirPath(QString &path, const QString &homeDir)
388 {
389 #ifdef Q_OS_WIN // safer
390     if (!QDir::toNativeSeparators(path).startsWith(QDir::toNativeSeparators(homeDir))) {
391         return false;
392     }
393 #else
394     if (!path.startsWith(homeDir)) {
395         return false;
396     }
397 #endif
398 
399     int len = homeDir.length();
400     // replace by "$HOME" if possible
401     if (len && (path.length() == len || path[len] == QLatin1Char('/'))) {
402         path.replace(0, len, QStringLiteral("$HOME"));
403         return true;
404     }
405 
406     return false;
407 }
408 
translatePath(QString path)409 static QString translatePath(QString path) // krazy:exclude=passbyvalue
410 {
411     if (path.isEmpty()) {
412         return path;
413     }
414 
415     // only "our" $HOME should be interpreted
416     path.replace(QLatin1Char('$'), QLatin1String("$$"));
417 
418     const bool startsWithFile = path.startsWith(QLatin1String("file:"), Qt::CaseInsensitive);
419     path = startsWithFile ? QUrl(path).toLocalFile() : path;
420 
421     if (QDir::isRelativePath(path)) {
422         return path;
423     }
424 
425     // we can not use KGlobal::dirs()->relativeLocation("home", path) here,
426     // since it would not recognize paths without a trailing '/'.
427     // All of the 3 following functions to return the user's home directory
428     // can return different paths. We have to test all them.
429     const QString homeDir0 = QFile::decodeName(qgetenv("HOME"));
430     const QString homeDir1 = QDir::homePath();
431     const QString homeDir2 = QDir(homeDir1).canonicalPath();
432     if (cleanHomeDirPath(path, homeDir0) || cleanHomeDirPath(path, homeDir1) || cleanHomeDirPath(path, homeDir2)) {
433         // qDebug() << "Path was replaced\n";
434     }
435 
436     if (startsWithFile) {
437         path = QUrl::fromLocalFile(path).toString();
438     }
439 
440     return path;
441 }
442 
KConfigGroup()443 KConfigGroup::KConfigGroup()
444     : d()
445 {
446 }
447 
isValid() const448 bool KConfigGroup::isValid() const
449 {
450     return bool(d);
451 }
452 
453 KConfigGroupGui _kde_internal_KConfigGroupGui;
readEntryGui(const QByteArray & data,const char * key,const QVariant & input,QVariant & output)454 static inline bool readEntryGui(const QByteArray &data, const char *key, const QVariant &input, QVariant &output)
455 {
456     if (_kde_internal_KConfigGroupGui.readEntryGui) {
457         return _kde_internal_KConfigGroupGui.readEntryGui(data, key, input, output);
458     }
459     return false;
460 }
461 
writeEntryGui(KConfigGroup * cg,const char * key,const QVariant & input,KConfigGroup::WriteConfigFlags flags)462 static inline bool writeEntryGui(KConfigGroup *cg, const char *key, const QVariant &input, KConfigGroup::WriteConfigFlags flags)
463 {
464     if (_kde_internal_KConfigGroupGui.writeEntryGui) {
465         return _kde_internal_KConfigGroupGui.writeEntryGui(cg, key, input, flags);
466     }
467     return false;
468 }
469 
KConfigGroup(KConfigBase * master,const QString & _group)470 KConfigGroup::KConfigGroup(KConfigBase *master, const QString &_group)
471     : d(KConfigGroupPrivate::create(master, _group.toUtf8(), master->isGroupImmutable(_group), false))
472 {
473 }
474 
KConfigGroup(KConfigBase * master,const char * _group)475 KConfigGroup::KConfigGroup(KConfigBase *master, const char *_group)
476     : d(KConfigGroupPrivate::create(master, _group, master->isGroupImmutable(_group), false))
477 {
478 }
479 
KConfigGroup(const KConfigBase * master,const QString & _group)480 KConfigGroup::KConfigGroup(const KConfigBase *master, const QString &_group)
481     : d(KConfigGroupPrivate::create(const_cast<KConfigBase *>(master), _group.toUtf8(), master->isGroupImmutable(_group), true))
482 {
483 }
484 
KConfigGroup(const KConfigBase * master,const char * _group)485 KConfigGroup::KConfigGroup(const KConfigBase *master, const char *_group)
486     : d(KConfigGroupPrivate::create(const_cast<KConfigBase *>(master), _group, master->isGroupImmutable(_group), true))
487 {
488 }
489 
KConfigGroup(const KSharedConfigPtr & master,const QString & _group)490 KConfigGroup::KConfigGroup(const KSharedConfigPtr &master, const QString &_group)
491     : d(new KConfigGroupPrivate(master, _group.toUtf8()))
492 {
493 }
494 
KConfigGroup(const KSharedConfigPtr & master,const char * _group)495 KConfigGroup::KConfigGroup(const KSharedConfigPtr &master, const char *_group)
496     : d(new KConfigGroupPrivate(master, _group))
497 {
498 }
499 
operator =(const KConfigGroup & rhs)500 KConfigGroup &KConfigGroup::operator=(const KConfigGroup &rhs)
501 {
502     d = rhs.d;
503     return *this;
504 }
505 
KConfigGroup(const KConfigGroup & rhs)506 KConfigGroup::KConfigGroup(const KConfigGroup &rhs)
507     : d(rhs.d)
508 {
509 }
510 
~KConfigGroup()511 KConfigGroup::~KConfigGroup()
512 {
513     d.reset();
514 }
515 
groupImpl(const QByteArray & aGroup)516 KConfigGroup KConfigGroup::groupImpl(const QByteArray &aGroup)
517 {
518     Q_ASSERT_X(isValid(), "KConfigGroup::groupImpl", "accessing an invalid group");
519     Q_ASSERT_X(!aGroup.isEmpty(), "KConfigGroup::groupImpl", "can not have an unnamed child group");
520 
521     KConfigGroup newGroup;
522 
523     newGroup.d = new KConfigGroupPrivate(this, isGroupImmutableImpl(aGroup), d->bConst, aGroup);
524 
525     return newGroup;
526 }
527 
groupImpl(const QByteArray & aGroup) const528 const KConfigGroup KConfigGroup::groupImpl(const QByteArray &aGroup) const
529 {
530     Q_ASSERT_X(isValid(), "KConfigGroup::groupImpl", "accessing an invalid group");
531     Q_ASSERT_X(!aGroup.isEmpty(), "KConfigGroup::groupImpl", "can not have an unnamed child group");
532 
533     KConfigGroup newGroup;
534 
535     newGroup.d = new KConfigGroupPrivate(const_cast<KConfigGroup *>(this), isGroupImmutableImpl(aGroup), true, aGroup);
536 
537     return newGroup;
538 }
539 
parent() const540 KConfigGroup KConfigGroup::parent() const
541 {
542     Q_ASSERT_X(isValid(), "KConfigGroup::parent", "accessing an invalid group");
543 
544     KConfigGroup parentGroup;
545 
546     if (d->mParent) {
547         parentGroup.d = d->mParent;
548     } else {
549         parentGroup.d = new KConfigGroupPrivate(d->mOwner, d->mOwner->isImmutable(), d->bConst, "");
550         // make sure we keep the refcount up on the KConfig object
551         parentGroup.d->sOwner = d->sOwner;
552     }
553 
554     return parentGroup;
555 }
556 
deleteGroup(WriteConfigFlags flags)557 void KConfigGroup::deleteGroup(WriteConfigFlags flags)
558 {
559     Q_ASSERT_X(isValid(), "KConfigGroup::deleteGroup", "accessing an invalid group");
560     Q_ASSERT_X(!d->bConst, "KConfigGroup::deleteGroup", "deleting a read-only group");
561 
562     config()->deleteGroup(d->fullName(), flags);
563 }
564 
565 #if KCONFIGCORE_BUILD_DEPRECATED_SINCE(5, 0)
changeGroup(const QString & group)566 void KConfigGroup::changeGroup(const QString &group)
567 {
568     Q_ASSERT_X(isValid(), "KConfigGroup::changeGroup", "accessing an invalid group");
569     d.detach();
570     d->mName = group.toUtf8();
571 }
572 #endif
573 
574 #if KCONFIGCORE_BUILD_DEPRECATED_SINCE(5, 0)
changeGroup(const char * group)575 void KConfigGroup::changeGroup(const char *group)
576 {
577     Q_ASSERT_X(isValid(), "KConfigGroup::changeGroup", "accessing an invalid group");
578     d.detach();
579     d->mName = group;
580 }
581 #endif
582 
name() const583 QString KConfigGroup::name() const
584 {
585     Q_ASSERT_X(isValid(), "KConfigGroup::name", "accessing an invalid group");
586 
587     return QString::fromUtf8(d->name());
588 }
589 
exists() const590 bool KConfigGroup::exists() const
591 {
592     Q_ASSERT_X(isValid(), "KConfigGroup::exists", "accessing an invalid group");
593 
594     return config()->hasGroup(d->fullName());
595 }
596 
sync()597 bool KConfigGroup::sync()
598 {
599     Q_ASSERT_X(isValid(), "KConfigGroup::sync", "accessing an invalid group");
600 
601     if (!d->bConst) {
602         return config()->sync();
603     }
604 
605     return false;
606 }
607 
entryMap() const608 QMap<QString, QString> KConfigGroup::entryMap() const
609 {
610     Q_ASSERT_X(isValid(), "KConfigGroup::entryMap", "accessing an invalid group");
611 
612     return config()->entryMap(QString::fromUtf8(d->fullName()));
613 }
614 
config()615 KConfig *KConfigGroup::config()
616 {
617     Q_ASSERT_X(isValid(), "KConfigGroup::config", "accessing an invalid group");
618 
619     return d->mOwner;
620 }
621 
config() const622 const KConfig *KConfigGroup::config() const
623 {
624     Q_ASSERT_X(isValid(), "KConfigGroup::config", "accessing an invalid group");
625 
626     return d->mOwner;
627 }
628 
isEntryImmutable(const char * key) const629 bool KConfigGroup::isEntryImmutable(const char *key) const
630 {
631     Q_ASSERT_X(isValid(), "KConfigGroup::isEntryImmutable", "accessing an invalid group");
632 
633     return (isImmutable() || !config()->d_func()->canWriteEntry(d->fullName(), key, config()->readDefaults()));
634 }
635 
isEntryImmutable(const QString & key) const636 bool KConfigGroup::isEntryImmutable(const QString &key) const
637 {
638     return isEntryImmutable(key.toUtf8().constData());
639 }
640 
readEntryUntranslated(const QString & pKey,const QString & aDefault) const641 QString KConfigGroup::readEntryUntranslated(const QString &pKey, const QString &aDefault) const
642 {
643     return readEntryUntranslated(pKey.toUtf8().constData(), aDefault);
644 }
645 
readEntryUntranslated(const char * key,const QString & aDefault) const646 QString KConfigGroup::readEntryUntranslated(const char *key, const QString &aDefault) const
647 {
648     Q_ASSERT_X(isValid(), "KConfigGroup::readEntryUntranslated", "accessing an invalid group");
649 
650     QString result = config()->d_func()->lookupData(d->fullName(), key, KEntryMap::SearchFlags(), nullptr);
651     if (result.isNull()) {
652         return aDefault;
653     }
654     return result;
655 }
656 
readEntry(const char * key,const char * aDefault) const657 QString KConfigGroup::readEntry(const char *key, const char *aDefault) const
658 {
659     return readEntry(key, QString::fromUtf8(aDefault));
660 }
661 
readEntry(const QString & key,const char * aDefault) const662 QString KConfigGroup::readEntry(const QString &key, const char *aDefault) const
663 {
664     return readEntry(key.toUtf8().constData(), aDefault);
665 }
666 
readEntry(const char * key,const QString & aDefault) const667 QString KConfigGroup::readEntry(const char *key, const QString &aDefault) const
668 {
669     Q_ASSERT_X(isValid(), "KConfigGroup::readEntry", "accessing an invalid group");
670 
671     bool expand = false;
672 
673     // read value from the entry map
674     QString aValue = config()->d_func()->lookupData(d->fullName(), key, KEntryMap::SearchLocalized, &expand);
675     if (aValue.isNull()) {
676         aValue = aDefault;
677     }
678 
679     if (expand) {
680         return KConfigPrivate::expandString(aValue);
681     }
682 
683     return aValue;
684 }
685 
readEntry(const QString & key,const QString & aDefault) const686 QString KConfigGroup::readEntry(const QString &key, const QString &aDefault) const
687 {
688     return readEntry(key.toUtf8().constData(), aDefault);
689 }
690 
readEntry(const char * key,const QStringList & aDefault) const691 QStringList KConfigGroup::readEntry(const char *key, const QStringList &aDefault) const
692 {
693     Q_ASSERT_X(isValid(), "KConfigGroup::readEntry", "accessing an invalid group");
694 
695     const QString data = readEntry(key, QString());
696     if (data.isNull()) {
697         return aDefault;
698     }
699 
700     return KConfigGroupPrivate::deserializeList(data);
701 }
702 
readEntry(const QString & key,const QStringList & aDefault) const703 QStringList KConfigGroup::readEntry(const QString &key, const QStringList &aDefault) const
704 {
705     return readEntry(key.toUtf8().constData(), aDefault);
706 }
707 
readEntry(const char * key,const QVariant & aDefault) const708 QVariant KConfigGroup::readEntry(const char *key, const QVariant &aDefault) const
709 {
710     Q_ASSERT_X(isValid(), "KConfigGroup::readEntry", "accessing an invalid group");
711 
712     const QByteArray data = config()->d_func()->lookupData(d->fullName(), key, KEntryMap::SearchLocalized);
713     if (data.isNull()) {
714         return aDefault;
715     }
716 
717     QVariant value;
718     if (!readEntryGui(data, key, aDefault, value)) {
719         return convertToQVariant(key, data, aDefault);
720     }
721 
722     return value;
723 }
724 
readEntry(const QString & key,const QVariant & aDefault) const725 QVariant KConfigGroup::readEntry(const QString &key, const QVariant &aDefault) const
726 {
727     return readEntry(key.toUtf8().constData(), aDefault);
728 }
729 
readEntry(const char * key,const QVariantList & aDefault) const730 QVariantList KConfigGroup::readEntry(const char *key, const QVariantList &aDefault) const
731 {
732     Q_ASSERT_X(isValid(), "KConfigGroup::readEntry", "accessing an invalid group");
733 
734     const QString data = readEntry(key, QString());
735     if (data.isNull()) {
736         return aDefault;
737     }
738 
739     const auto &list = KConfigGroupPrivate::deserializeList(data);
740 
741     QVariantList value;
742     value.reserve(list.count());
743     for (const QString &v : list) {
744         value << v;
745     }
746 
747     return value;
748 }
749 
readEntry(const QString & key,const QVariantList & aDefault) const750 QVariantList KConfigGroup::readEntry(const QString &key, const QVariantList &aDefault) const
751 {
752     return readEntry(key.toUtf8().constData(), aDefault);
753 }
754 
readXdgListEntry(const QString & key,const QStringList & aDefault) const755 QStringList KConfigGroup::readXdgListEntry(const QString &key, const QStringList &aDefault) const
756 {
757     return readXdgListEntry(key.toUtf8().constData(), aDefault);
758 }
759 
readXdgListEntry(const char * key,const QStringList & aDefault) const760 QStringList KConfigGroup::readXdgListEntry(const char *key, const QStringList &aDefault) const
761 {
762     Q_ASSERT_X(isValid(), "KConfigGroup::readXdgListEntry", "accessing an invalid group");
763 
764     const QString data = readEntry(key, QString());
765     if (data.isNull()) {
766         return aDefault;
767     }
768 
769     QStringList value;
770     QString val;
771     val.reserve(data.size());
772     // XXX List serialization being a separate layer from low-level parsing is
773     // probably a bug. No affected entries are defined, though.
774     bool quoted = false;
775     for (int p = 0; p < data.length(); p++) {
776         if (quoted) {
777             val += data[p];
778             quoted = false;
779         } else if (data[p] == QLatin1Char('\\')) {
780             quoted = true;
781         } else if (data[p] == QLatin1Char(';')) {
782             value.append(val);
783             val.clear();
784             val.reserve(data.size() - p);
785         } else {
786             val += data[p];
787         }
788     }
789     if (!val.isEmpty()) {
790         value.append(val);
791     }
792     return value;
793 }
794 
readPathEntry(const QString & pKey,const QString & aDefault) const795 QString KConfigGroup::readPathEntry(const QString &pKey, const QString &aDefault) const
796 {
797     return readPathEntry(pKey.toUtf8().constData(), aDefault);
798 }
799 
readPathEntry(const char * key,const QString & aDefault) const800 QString KConfigGroup::readPathEntry(const char *key, const QString &aDefault) const
801 {
802     Q_ASSERT_X(isValid(), "KConfigGroup::readPathEntry", "accessing an invalid group");
803 
804     bool expand = false;
805 
806     QString aValue = config()->d_func()->lookupData(d->fullName(), key, KEntryMap::SearchLocalized, &expand);
807     if (aValue.isNull()) {
808         aValue = aDefault;
809     }
810 
811     return KConfigPrivate::expandString(aValue);
812 }
813 
readPathEntry(const QString & pKey,const QStringList & aDefault) const814 QStringList KConfigGroup::readPathEntry(const QString &pKey, const QStringList &aDefault) const
815 {
816     return readPathEntry(pKey.toUtf8().constData(), aDefault);
817 }
818 
readPathEntry(const char * key,const QStringList & aDefault) const819 QStringList KConfigGroup::readPathEntry(const char *key, const QStringList &aDefault) const
820 {
821     Q_ASSERT_X(isValid(), "KConfigGroup::readPathEntry", "accessing an invalid group");
822 
823     const QString data = readPathEntry(key, QString());
824     if (data.isNull()) {
825         return aDefault;
826     }
827 
828     return KConfigGroupPrivate::deserializeList(data);
829 }
830 
writeEntry(const char * key,const QString & value,WriteConfigFlags flags)831 void KConfigGroup::writeEntry(const char *key, const QString &value, WriteConfigFlags flags)
832 {
833     Q_ASSERT_X(isValid(), "KConfigGroup::writeEntry", "accessing an invalid group");
834     Q_ASSERT_X(!d->bConst, "KConfigGroup::writeEntry", "writing to a read-only group");
835 
836     writeEntry(key, value.toUtf8(), flags);
837 }
838 
writeEntry(const QString & key,const QString & value,WriteConfigFlags flags)839 void KConfigGroup::writeEntry(const QString &key, const QString &value, WriteConfigFlags flags)
840 {
841     writeEntry(key.toUtf8().constData(), value, flags);
842 }
843 
writeEntry(const QString & key,const char * value,WriteConfigFlags pFlags)844 void KConfigGroup::writeEntry(const QString &key, const char *value, WriteConfigFlags pFlags)
845 {
846     Q_ASSERT_X(isValid(), "KConfigGroup::writeEntry", "accessing an invalid group");
847     Q_ASSERT_X(!d->bConst, "KConfigGroup::writeEntry", "writing to a read-only group");
848 
849     writeEntry(key.toUtf8().constData(), QVariant(QString::fromLatin1(value)), pFlags);
850 }
851 
writeEntry(const char * key,const char * value,WriteConfigFlags pFlags)852 void KConfigGroup::writeEntry(const char *key, const char *value, WriteConfigFlags pFlags)
853 {
854     writeEntry(key, QVariant(QString::fromLatin1(value)), pFlags);
855 }
856 
writeEntry(const char * key,const QByteArray & value,WriteConfigFlags flags)857 void KConfigGroup::writeEntry(const char *key, const QByteArray &value, WriteConfigFlags flags)
858 {
859     Q_ASSERT_X(isValid(), "KConfigGroup::writeEntry", "accessing an invalid group");
860     Q_ASSERT_X(!d->bConst, "KConfigGroup::writeEntry", "writing to a read-only group");
861 
862     config()->d_func()->putData(d->fullName(), key, value.isNull() ? QByteArray("") : value, flags);
863 }
864 
writeEntry(const QString & key,const QByteArray & value,WriteConfigFlags pFlags)865 void KConfigGroup::writeEntry(const QString &key, const QByteArray &value, WriteConfigFlags pFlags)
866 {
867     writeEntry(key.toUtf8().constData(), value, pFlags);
868 }
869 
writeEntry(const char * key,const QStringList & list,WriteConfigFlags flags)870 void KConfigGroup::writeEntry(const char *key, const QStringList &list, WriteConfigFlags flags)
871 {
872     Q_ASSERT_X(isValid(), "KConfigGroup::writeEntry", "accessing an invalid group");
873     Q_ASSERT_X(!d->bConst, "KConfigGroup::writeEntry", "writing to a read-only group");
874 
875     QList<QByteArray> balist;
876     balist.reserve(list.count());
877 
878     for (const QString &entry : list) {
879         balist.append(entry.toUtf8());
880     }
881 
882     writeEntry(key, KConfigGroupPrivate::serializeList(balist), flags);
883 }
884 
writeEntry(const QString & key,const QStringList & list,WriteConfigFlags flags)885 void KConfigGroup::writeEntry(const QString &key, const QStringList &list, WriteConfigFlags flags)
886 {
887     writeEntry(key.toUtf8().constData(), list, flags);
888 }
889 
writeEntry(const char * key,const QVariantList & list,WriteConfigFlags flags)890 void KConfigGroup::writeEntry(const char *key, const QVariantList &list, WriteConfigFlags flags)
891 {
892     Q_ASSERT_X(isValid(), "KConfigGroup::writeEntry", "accessing an invalid group");
893     Q_ASSERT_X(!d->bConst, "KConfigGroup::writeEntry", "writing to a read-only group");
894 
895     QList<QByteArray> data;
896     data.reserve(list.count());
897 
898     for (const QVariant &v : list) {
899         if (v.type() == QVariant::ByteArray) {
900             data << v.toByteArray();
901         } else {
902             data << v.toString().toUtf8();
903         }
904     }
905 
906     writeEntry(key, KConfigGroupPrivate::serializeList(data), flags);
907 }
908 
writeEntry(const char * key,const QVariant & value,WriteConfigFlags flags)909 void KConfigGroup::writeEntry(const char *key, const QVariant &value, WriteConfigFlags flags)
910 {
911     Q_ASSERT_X(isValid(), "KConfigGroup::writeEntry", "accessing an invalid group");
912     Q_ASSERT_X(!d->bConst, "KConfigGroup::writeEntry", "writing to a read-only group");
913 
914     if (writeEntryGui(this, key, value, flags)) {
915         return; // GUI type that was handled
916     }
917 
918     QByteArray data;
919     // if a type handler is added here you must add a QVConversions definition
920     // to conversioncheck.h, or ConversionCheck::to_QVariant will not allow
921     // writeEntry<T> to convert to QVariant.
922     switch (static_cast<QMetaType::Type>(value.type())) {
923     case QMetaType::UnknownType:
924         data = "";
925         break;
926     case QMetaType::QByteArray:
927         data = value.toByteArray();
928         break;
929     case QMetaType::QString:
930     case QMetaType::Int:
931     case QMetaType::UInt:
932     case QMetaType::Double:
933     case QMetaType::Float:
934     case QMetaType::Bool:
935     case QMetaType::LongLong:
936     case QMetaType::ULongLong:
937         data = value.toString().toUtf8();
938         break;
939     case QMetaType::QVariantList:
940         if (!value.canConvert(QMetaType::QStringList)) {
941             qCWarning(KCONFIG_CORE_LOG) << "not all types in \"" << key
942                                         << "\" can convert to QString,"
943                                            " information will be lost";
944         }
945         Q_FALLTHROUGH();
946     case QMetaType::QStringList:
947         writeEntry(key, value.toList(), flags);
948         return;
949     case QMetaType::QPoint: {
950         const QPoint rPoint = value.toPoint();
951 
952         const QVariantList list{rPoint.x(), rPoint.y()};
953 
954         writeEntry(key, list, flags);
955         return;
956     }
957     case QMetaType::QPointF: {
958         const QPointF point = value.toPointF();
959 
960         const QVariantList list{point.x(), point.y()};
961 
962         writeEntry(key, list, flags);
963         return;
964     }
965     case QMetaType::QRect: {
966         const QRect rRect = value.toRect();
967 
968         const QVariantList list{rRect.left(), rRect.top(), rRect.width(), rRect.height()};
969 
970         writeEntry(key, list, flags);
971         return;
972     }
973     case QMetaType::QRectF: {
974         const QRectF rRectF = value.toRectF();
975 
976         const QVariantList list{rRectF.left(), rRectF.top(), rRectF.width(), rRectF.height()};
977 
978         writeEntry(key, list, flags);
979         return;
980     }
981     case QMetaType::QSize: {
982         const QSize rSize = value.toSize();
983 
984         const QVariantList list{rSize.width(), rSize.height()};
985 
986         writeEntry(key, list, flags);
987         return;
988     }
989     case QMetaType::QSizeF: {
990         const QSizeF rSizeF = value.toSizeF();
991 
992         const QVariantList list{rSizeF.width(), rSizeF.height()};
993 
994         writeEntry(key, list, flags);
995         return;
996     }
997     case QMetaType::QDate: {
998         const QDate date = value.toDate();
999 
1000         const QVariantList list{date.year(), date.month(), date.day()};
1001 
1002         writeEntry(key, list, flags);
1003         return;
1004     }
1005     case QMetaType::QDateTime: {
1006         const QDateTime rDateTime = value.toDateTime();
1007 
1008         const QTime time = rDateTime.time();
1009         const QDate date = rDateTime.date();
1010 
1011         const QVariantList list{
1012             date.year(),
1013             date.month(),
1014             date.day(),
1015 
1016             time.hour(),
1017             time.minute(),
1018             time.second() + time.msec() / 1000.0,
1019         };
1020 
1021         writeEntry(key, list, flags);
1022         return;
1023     }
1024 
1025     case QMetaType::QColor:
1026     case QMetaType::QFont:
1027         qCWarning(KCONFIG_CORE_LOG) << "KConfigGroup::writeEntry was passed GUI type '" << value.typeName()
1028                                     << "' but KConfigGui isn't linked! If it is linked to your program, this is a platform bug. "
1029                                        "Please inform the KDE developers";
1030         break;
1031     case QMetaType::QUrl:
1032         data = QUrl(value.toUrl()).toString().toUtf8();
1033         break;
1034     default:
1035         qCWarning(KCONFIG_CORE_LOG) << "KConfigGroup::writeEntry - unhandled type" << value.typeName() << "in group" << name();
1036     }
1037 
1038     writeEntry(key, data, flags);
1039 }
1040 
writeEntry(const QString & key,const QVariant & value,WriteConfigFlags flags)1041 void KConfigGroup::writeEntry(const QString &key, const QVariant &value, WriteConfigFlags flags)
1042 {
1043     writeEntry(key.toUtf8().constData(), value, flags);
1044 }
1045 
writeEntry(const QString & key,const QVariantList & list,WriteConfigFlags flags)1046 void KConfigGroup::writeEntry(const QString &key, const QVariantList &list, WriteConfigFlags flags)
1047 {
1048     writeEntry(key.toUtf8().constData(), list, flags);
1049 }
1050 
writeXdgListEntry(const QString & key,const QStringList & value,WriteConfigFlags pFlags)1051 void KConfigGroup::writeXdgListEntry(const QString &key, const QStringList &value, WriteConfigFlags pFlags)
1052 {
1053     writeXdgListEntry(key.toUtf8().constData(), value, pFlags);
1054 }
1055 
writeXdgListEntry(const char * key,const QStringList & list,WriteConfigFlags flags)1056 void KConfigGroup::writeXdgListEntry(const char *key, const QStringList &list, WriteConfigFlags flags)
1057 {
1058     Q_ASSERT_X(isValid(), "KConfigGroup::writeXdgListEntry", "accessing an invalid group");
1059     Q_ASSERT_X(!d->bConst, "KConfigGroup::writeXdgListEntry", "writing to a read-only group");
1060 
1061     QString value;
1062     value.reserve(4096);
1063 
1064     // XXX List serialization being a separate layer from low-level escaping is
1065     // probably a bug. No affected entries are defined, though.
1066     for (QString val : list) { // clazy:exclude=range-loop
1067         val.replace(QLatin1Char('\\'), QLatin1String("\\\\")).replace(QLatin1Char(';'), QLatin1String("\\;"));
1068         value += val + QLatin1Char(';');
1069     }
1070 
1071     writeEntry(key, value, flags);
1072 }
1073 
writePathEntry(const QString & pKey,const QString & path,WriteConfigFlags pFlags)1074 void KConfigGroup::writePathEntry(const QString &pKey, const QString &path, WriteConfigFlags pFlags)
1075 {
1076     writePathEntry(pKey.toUtf8().constData(), path, pFlags);
1077 }
1078 
writePathEntry(const char * pKey,const QString & path,WriteConfigFlags pFlags)1079 void KConfigGroup::writePathEntry(const char *pKey, const QString &path, WriteConfigFlags pFlags)
1080 {
1081     Q_ASSERT_X(isValid(), "KConfigGroup::writePathEntry", "accessing an invalid group");
1082     Q_ASSERT_X(!d->bConst, "KConfigGroup::writePathEntry", "writing to a read-only group");
1083 
1084     config()->d_func()->putData(d->fullName(), pKey, translatePath(path).toUtf8(), pFlags, true);
1085 }
1086 
writePathEntry(const QString & pKey,const QStringList & value,WriteConfigFlags pFlags)1087 void KConfigGroup::writePathEntry(const QString &pKey, const QStringList &value, WriteConfigFlags pFlags)
1088 {
1089     writePathEntry(pKey.toUtf8().constData(), value, pFlags);
1090 }
1091 
writePathEntry(const char * pKey,const QStringList & value,WriteConfigFlags pFlags)1092 void KConfigGroup::writePathEntry(const char *pKey, const QStringList &value, WriteConfigFlags pFlags)
1093 {
1094     Q_ASSERT_X(isValid(), "KConfigGroup::writePathEntry", "accessing an invalid group");
1095     Q_ASSERT_X(!d->bConst, "KConfigGroup::writePathEntry", "writing to a read-only group");
1096 
1097     QList<QByteArray> list;
1098     list.reserve(value.length());
1099     for (const QString &path : value) {
1100         list << translatePath(path).toUtf8();
1101     }
1102 
1103     config()->d_func()->putData(d->fullName(), pKey, KConfigGroupPrivate::serializeList(list), pFlags, true);
1104 }
1105 
deleteEntry(const char * key,WriteConfigFlags flags)1106 void KConfigGroup::deleteEntry(const char *key, WriteConfigFlags flags)
1107 {
1108     Q_ASSERT_X(isValid(), "KConfigGroup::deleteEntry", "accessing an invalid group");
1109     Q_ASSERT_X(!d->bConst, "KConfigGroup::deleteEntry", "deleting from a read-only group");
1110 
1111     config()->d_func()->putData(d->fullName(), key, QByteArray(), flags);
1112 }
1113 
deleteEntry(const QString & key,WriteConfigFlags flags)1114 void KConfigGroup::deleteEntry(const QString &key, WriteConfigFlags flags)
1115 {
1116     deleteEntry(key.toUtf8().constData(), flags);
1117 }
1118 
revertToDefault(const char * key)1119 void KConfigGroup::revertToDefault(const char *key)
1120 {
1121     revertToDefault(key, WriteConfigFlags());
1122 }
1123 
revertToDefault(const char * key,WriteConfigFlags flags)1124 void KConfigGroup::revertToDefault(const char *key, WriteConfigFlags flags)
1125 {
1126     Q_ASSERT_X(isValid(), "KConfigGroup::revertToDefault", "accessing an invalid group");
1127     Q_ASSERT_X(!d->bConst, "KConfigGroup::revertToDefault", "writing to a read-only group");
1128 
1129     config()->d_func()->revertEntry(d->fullName(), key, flags);
1130 }
1131 
revertToDefault(const QString & key)1132 void KConfigGroup::revertToDefault(const QString &key)
1133 {
1134     revertToDefault(key, WriteConfigFlags());
1135 }
1136 
revertToDefault(const QString & key,WriteConfigFlags flags)1137 void KConfigGroup::revertToDefault(const QString &key, WriteConfigFlags flags)
1138 {
1139     revertToDefault(key.toUtf8().constData(), flags);
1140 }
1141 
hasDefault(const char * key) const1142 bool KConfigGroup::hasDefault(const char *key) const
1143 {
1144     Q_ASSERT_X(isValid(), "KConfigGroup::hasDefault", "accessing an invalid group");
1145 
1146     KEntryMap::SearchFlags flags = KEntryMap::SearchDefaults | KEntryMap::SearchLocalized;
1147 
1148     return !config()->d_func()->lookupData(d->fullName(), key, flags).isNull();
1149 }
1150 
hasDefault(const QString & key) const1151 bool KConfigGroup::hasDefault(const QString &key) const
1152 {
1153     return hasDefault(key.toUtf8().constData());
1154 }
1155 
hasKey(const char * key) const1156 bool KConfigGroup::hasKey(const char *key) const
1157 {
1158     Q_ASSERT_X(isValid(), "KConfigGroup::hasKey", "accessing an invalid group");
1159 
1160     KEntryMap::SearchFlags flags = KEntryMap::SearchLocalized;
1161     if (config()->readDefaults()) {
1162         flags |= KEntryMap::SearchDefaults;
1163     }
1164 
1165     return !config()->d_func()->lookupData(d->fullName(), key, flags).isNull();
1166 }
1167 
hasKey(const QString & key) const1168 bool KConfigGroup::hasKey(const QString &key) const
1169 {
1170     return hasKey(key.toUtf8().constData());
1171 }
1172 
isImmutable() const1173 bool KConfigGroup::isImmutable() const
1174 {
1175     Q_ASSERT_X(isValid(), "KConfigGroup::isImmutable", "accessing an invalid group");
1176 
1177     return d->bImmutable;
1178 }
1179 
groupList() const1180 QStringList KConfigGroup::groupList() const
1181 {
1182     Q_ASSERT_X(isValid(), "KConfigGroup::groupList", "accessing an invalid group");
1183 
1184     return config()->d_func()->groupList(d->fullName());
1185 }
1186 
keyList() const1187 QStringList KConfigGroup::keyList() const
1188 {
1189     Q_ASSERT_X(isValid(), "KConfigGroup::keyList", "accessing an invalid group");
1190 
1191     return entryMap().keys();
1192 }
1193 
markAsClean()1194 void KConfigGroup::markAsClean()
1195 {
1196     Q_ASSERT_X(isValid(), "KConfigGroup::markAsClean", "accessing an invalid group");
1197 
1198     config()->markAsClean();
1199 }
1200 
accessMode() const1201 KConfigGroup::AccessMode KConfigGroup::accessMode() const
1202 {
1203     Q_ASSERT_X(isValid(), "KConfigGroup::accessMode", "accessing an invalid group");
1204 
1205     return config()->accessMode();
1206 }
1207 
hasGroupImpl(const QByteArray & b) const1208 bool KConfigGroup::hasGroupImpl(const QByteArray &b) const
1209 {
1210     Q_ASSERT_X(isValid(), "KConfigGroup::hasGroupImpl", "accessing an invalid group");
1211 
1212     return config()->hasGroup(d->fullName(b));
1213 }
1214 
deleteGroupImpl(const QByteArray & b,WriteConfigFlags flags)1215 void KConfigGroup::deleteGroupImpl(const QByteArray &b, WriteConfigFlags flags)
1216 {
1217     Q_ASSERT_X(isValid(), "KConfigGroup::deleteGroupImpl", "accessing an invalid group");
1218     Q_ASSERT_X(!d->bConst, "KConfigGroup::deleteGroupImpl", "deleting from a read-only group");
1219 
1220     config()->deleteGroup(d->fullName(b), flags);
1221 }
1222 
isGroupImmutableImpl(const QByteArray & b) const1223 bool KConfigGroup::isGroupImmutableImpl(const QByteArray &b) const
1224 {
1225     Q_ASSERT_X(isValid(), "KConfigGroup::isGroupImmutableImpl", "accessing an invalid group");
1226 
1227     if (!hasGroupImpl(b)) { // group doesn't exist yet
1228         return d->bImmutable; // child groups are immutable if the parent is immutable.
1229     }
1230 
1231     return config()->isGroupImmutable(d->fullName(b));
1232 }
1233 
copyTo(KConfigBase * other,WriteConfigFlags pFlags) const1234 void KConfigGroup::copyTo(KConfigBase *other, WriteConfigFlags pFlags) const
1235 {
1236     Q_ASSERT_X(isValid(), "KConfigGroup::copyTo", "accessing an invalid group");
1237     Q_ASSERT(other != nullptr);
1238 
1239     if (KConfigGroup *otherGroup = dynamic_cast<KConfigGroup *>(other)) {
1240         config()->d_func()->copyGroup(d->fullName(), otherGroup->d->fullName(), otherGroup, pFlags);
1241     } else if (KConfig *otherConfig = dynamic_cast<KConfig *>(other)) {
1242         KConfigGroup newGroup = otherConfig->group(d->fullName());
1243         otherConfig->d_func()->copyGroup(d->fullName(), d->fullName(), &newGroup, pFlags);
1244     } else {
1245         Q_ASSERT_X(false, "KConfigGroup::copyTo", "unknown type of KConfigBase");
1246     }
1247 }
1248 
reparent(KConfigBase * parent,WriteConfigFlags pFlags)1249 void KConfigGroup::reparent(KConfigBase *parent, WriteConfigFlags pFlags)
1250 {
1251     Q_ASSERT_X(isValid(), "KConfigGroup::reparent", "accessing an invalid group");
1252     Q_ASSERT_X(!d->bConst, "KConfigGroup::reparent", "reparenting a read-only group");
1253     Q_ASSERT_X(!d->bImmutable, "KConfigGroup::reparent", "reparenting an immutable group");
1254     Q_ASSERT(parent != nullptr);
1255 
1256     KConfigGroup oldGroup(*this);
1257 
1258     d = KConfigGroupPrivate::create(parent, d->mName, false, false);
1259     oldGroup.copyTo(this, pFlags);
1260     oldGroup.deleteGroup(); // so that the entries with the old group name are deleted on sync
1261 }
1262 
moveValuesTo(const QList<const char * > & keys,KConfigGroup & other,WriteConfigFlags pFlags)1263 void KConfigGroup::moveValuesTo(const QList<const char *> &keys, KConfigGroup &other, WriteConfigFlags pFlags)
1264 {
1265     Q_ASSERT(isValid());
1266     Q_ASSERT(other.isValid());
1267 
1268     for (const auto key : keys) {
1269         const QByteArray groupName = name().toLocal8Bit();
1270         const auto entry = config()->d_ptr->lookupInternalEntry(groupName, key, KEntryMap::SearchLocalized);
1271 
1272         // Only write the entry if it is not null, if it is a global enry there is no point in moving it
1273         if (!entry.mValue.isNull() && !entry.bGlobal) {
1274             deleteEntry(key, pFlags);
1275             KEntryMap::EntryOptions options = KEntryMap::EntryOption::EntryDirty;
1276             if (entry.bDeleted) {
1277                 options |= KEntryMap::EntryDeleted;
1278             }
1279 
1280             if (entry.bExpand) {
1281                 options |= KEntryMap::EntryExpansion;
1282             }
1283 
1284             other.config()->d_ptr->setEntryData(other.name().toLocal8Bit(), key, entry.mValue, options);
1285         }
1286     }
1287 }
1288