Coverage Report

Created: 2023-06-07 06:33

/src/qtbase/src/corelib/io/qsettings.cpp
Line
Count
Source (jump to first uncovered line)
1
/****************************************************************************
2
**
3
** Copyright (C) 2022 The Qt Company Ltd.
4
** Contact: https://www.qt.io/licensing/
5
**
6
** This file is part of the QtCore module of the Qt Toolkit.
7
**
8
** $QT_BEGIN_LICENSE:LGPL$
9
** Commercial License Usage
10
** Licensees holding valid commercial Qt licenses may use this file in
11
** accordance with the commercial license agreement provided with the
12
** Software or, alternatively, in accordance with the terms contained in
13
** a written agreement between you and The Qt Company. For licensing terms
14
** and conditions see https://www.qt.io/terms-conditions. For further
15
** information use the contact form at https://www.qt.io/contact-us.
16
**
17
** GNU Lesser General Public License Usage
18
** Alternatively, this file may be used under the terms of the GNU Lesser
19
** General Public License version 3 as published by the Free Software
20
** Foundation and appearing in the file LICENSE.LGPL3 included in the
21
** packaging of this file. Please review the following information to
22
** ensure the GNU Lesser General Public License version 3 requirements
23
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24
**
25
** GNU General Public License Usage
26
** Alternatively, this file may be used under the terms of the GNU
27
** General Public License version 2.0 or (at your option) the GNU General
28
** Public license version 3 or any later version approved by the KDE Free
29
** Qt Foundation. The licenses are as published by the Free Software
30
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31
** included in the packaging of this file. Please review the following
32
** information to ensure the GNU General Public License requirements will
33
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34
** https://www.gnu.org/licenses/gpl-3.0.html.
35
**
36
** $QT_END_LICENSE$
37
**
38
****************************************************************************/
39
40
#include <qdebug.h>
41
#include "qplatformdefs.h"
42
#include "qsettings.h"
43
44
#include "qsettings_p.h"
45
#include "qcache.h"
46
#include "qfile.h"
47
#include "qdir.h"
48
#include "qfileinfo.h"
49
#include "qmutex.h"
50
#include "private/qlocking_p.h"
51
#include "qlibraryinfo.h"
52
#include "qtemporaryfile.h"
53
#include "qstandardpaths.h"
54
#include <qdatastream.h>
55
56
#if QT_CONFIG(textcodec)
57
#  include "qtextcodec.h"
58
#endif
59
60
#ifndef QT_NO_GEOM_VARIANT
61
#include "qsize.h"
62
#include "qpoint.h"
63
#include "qrect.h"
64
#endif // !QT_NO_GEOM_VARIANT
65
66
#ifndef QT_BUILD_QMAKE
67
#  include "qcoreapplication.h"
68
#endif
69
70
#ifndef QT_BOOTSTRAPPED
71
#include "qsavefile.h"
72
#include "qlockfile.h"
73
#endif
74
75
#ifdef Q_OS_VXWORKS
76
#  include <ioLib.h>
77
#endif
78
79
#include <algorithm>
80
#include <stdlib.h>
81
82
#ifdef Q_OS_WIN // for homedirpath reading from registry
83
#  include <qt_windows.h>
84
#  ifndef Q_OS_WINRT
85
#    include <shlobj.h>
86
#  endif
87
#endif
88
89
#ifdef Q_OS_WINRT
90
#include <wrl.h>
91
#include <windows.foundation.h>
92
#include <windows.storage.h>
93
using namespace Microsoft::WRL;
94
using namespace Microsoft::WRL::Wrappers;
95
using namespace ABI::Windows::Foundation;
96
using namespace ABI::Windows::Storage;
97
#endif
98
99
#if defined(Q_OS_UNIX) && !defined(Q_OS_MAC) && !defined(Q_OS_ANDROID)
100
#define Q_XDG_PLATFORM
101
#endif
102
103
#if !defined(QT_NO_STANDARDPATHS) && (defined(Q_XDG_PLATFORM) || defined(QT_PLATFORM_UIKIT))
104
#define QSETTINGS_USE_QSTANDARDPATHS
105
#endif
106
107
// ************************************************************************
108
// QConfFile
109
110
/*
111
    QConfFile objects are explicitly shared within the application.
112
    This ensures that modification to the settings done through one
113
    QSettings object are immediately reflected in other setting
114
    objects of the same application.
115
*/
116
117
QT_BEGIN_NAMESPACE
118
119
struct QConfFileCustomFormat
120
{
121
    QString extension;
122
    QSettings::ReadFunc readFunc;
123
    QSettings::WriteFunc writeFunc;
124
    Qt::CaseSensitivity caseSensitivity;
125
};
126
Q_DECLARE_TYPEINFO(QConfFileCustomFormat, Q_MOVABLE_TYPE);
127
128
typedef QHash<QString, QConfFile *> ConfFileHash;
129
typedef QCache<QString, QConfFile> ConfFileCache;
130
namespace {
131
    struct Path
132
    {
133
        // Note: Defining constructors explicitly because of buggy C++11
134
        // implementation in MSVC (uniform initialization).
135
0
        Path() {}
136
0
        Path(const QString & p, bool ud) : path(p), userDefined(ud) {}
137
        QString path;
138
        bool userDefined; //!< true - user defined, overridden by setPath
139
    };
140
}
141
typedef QHash<int, Path> PathHash;
142
typedef QVector<QConfFileCustomFormat> CustomFormatVector;
143
144
Q_GLOBAL_STATIC(ConfFileHash, usedHashFunc)
145
Q_GLOBAL_STATIC(ConfFileCache, unusedCacheFunc)
146
Q_GLOBAL_STATIC(PathHash, pathHashFunc)
147
Q_GLOBAL_STATIC(CustomFormatVector, customFormatVectorFunc)
148
149
static QBasicMutex settingsGlobalMutex;
150
151
static QSettings::Format globalDefaultFormat = QSettings::NativeFormat;
152
153
QConfFile::QConfFile(const QString &fileName, bool _userPerms)
154
    : name(fileName), size(0), ref(1), userPerms(_userPerms)
155
0
{
156
0
    usedHashFunc()->insert(name, this);
157
0
}
158
159
QConfFile::~QConfFile()
160
0
{
161
0
    if (usedHashFunc())
162
0
        usedHashFunc()->remove(name);
163
0
}
164
165
ParsedSettingsMap QConfFile::mergedKeyMap() const
166
0
{
167
0
    ParsedSettingsMap result = originalKeys;
168
0
    ParsedSettingsMap::const_iterator i;
169
170
0
    for (i = removedKeys.begin(); i != removedKeys.end(); ++i)
171
0
        result.remove(i.key());
172
0
    for (i = addedKeys.begin(); i != addedKeys.end(); ++i)
173
0
        result.insert(i.key(), i.value());
174
0
    return result;
175
0
}
176
177
bool QConfFile::isWritable() const
178
0
{
179
0
    QFileInfo fileInfo(name);
180
181
0
#ifndef QT_NO_TEMPORARYFILE
182
0
    if (fileInfo.exists()) {
183
0
#endif
184
0
        QFile file(name);
185
0
        return file.open(QFile::ReadWrite);
186
0
#ifndef QT_NO_TEMPORARYFILE
187
0
    } else {
188
        // Create the directories to the file.
189
0
        QDir dir(fileInfo.absolutePath());
190
0
        if (!dir.exists()) {
191
0
            if (!dir.mkpath(dir.absolutePath()))
192
0
                return false;
193
0
        }
194
195
        // we use a temporary file to avoid race conditions
196
0
        QTemporaryFile file(name);
197
0
        return file.open();
198
0
    }
199
0
#endif
200
0
}
201
202
QConfFile *QConfFile::fromName(const QString &fileName, bool _userPerms)
203
0
{
204
0
    QString absPath = QFileInfo(fileName).absoluteFilePath();
205
206
0
    ConfFileHash *usedHash = usedHashFunc();
207
0
    ConfFileCache *unusedCache = unusedCacheFunc();
208
209
0
    QConfFile *confFile = nullptr;
210
0
    const auto locker = qt_scoped_lock(settingsGlobalMutex);
211
212
0
    if (!(confFile = usedHash->value(absPath))) {
213
0
        if ((confFile = unusedCache->take(absPath)))
214
0
            usedHash->insert(absPath, confFile);
215
0
    }
216
0
    if (confFile) {
217
0
        confFile->ref.ref();
218
0
        return confFile;
219
0
    }
220
0
    return new QConfFile(absPath, _userPerms);
221
0
}
222
223
void QConfFile::clearCache()
224
0
{
225
0
    const auto locker = qt_scoped_lock(settingsGlobalMutex);
226
0
    unusedCacheFunc()->clear();
227
0
}
228
229
// ************************************************************************
230
// QSettingsPrivate
231
232
QSettingsPrivate::QSettingsPrivate(QSettings::Format format)
233
    : format(format), scope(QSettings::UserScope /* nothing better to put */), iniCodec(nullptr), fallbacks(true),
234
      pendingChanges(false), status(QSettings::NoError)
235
0
{
236
0
}
237
238
QSettingsPrivate::QSettingsPrivate(QSettings::Format format, QSettings::Scope scope,
239
                                   const QString &organization, const QString &application)
240
    : format(format), scope(scope), organizationName(organization), applicationName(application),
241
      iniCodec(nullptr), fallbacks(true), pendingChanges(false), status(QSettings::NoError)
242
0
{
243
0
}
244
245
QSettingsPrivate::~QSettingsPrivate()
246
0
{
247
0
}
248
249
QString QSettingsPrivate::actualKey(const QString &key) const
250
0
{
251
0
    QString n = normalizedKey(key);
252
0
    Q_ASSERT_X(!n.isEmpty(), "QSettings", "empty key");
253
0
    return groupPrefix + n;
254
0
}
255
256
/*
257
    Returns a string that never starts nor ends with a slash (or an
258
    empty string). Examples:
259
260
            "foo"            becomes   "foo"
261
            "/foo//bar///"   becomes   "foo/bar"
262
            "///"            becomes   ""
263
264
    This function is optimized to avoid a QString deep copy in the
265
    common case where the key is already normalized.
266
*/
267
QString QSettingsPrivate::normalizedKey(const QString &key)
268
0
{
269
0
    QString result = key;
270
271
0
    int i = 0;
272
0
    while (i < result.size()) {
273
0
        while (result.at(i) == QLatin1Char('/')) {
274
0
            result.remove(i, 1);
275
0
            if (i == result.size())
276
0
                goto after_loop;
277
0
        }
278
0
        while (result.at(i) != QLatin1Char('/')) {
279
0
            ++i;
280
0
            if (i == result.size())
281
0
                return result;
282
0
        }
283
0
        ++i; // leave the slash alone
284
0
    }
285
286
0
after_loop:
287
0
    if (!result.isEmpty())
288
0
        result.truncate(i - 1); // remove the trailing slash
289
0
    return result;
290
0
}
291
292
// see also qsettings_win.cpp, qsettings_winrt.cpp and qsettings_mac.cpp
293
294
#if !defined(Q_OS_WIN) && !defined(Q_OS_MAC) && !defined(Q_OS_WASM)
295
QSettingsPrivate *QSettingsPrivate::create(QSettings::Format format, QSettings::Scope scope,
296
                                           const QString &organization, const QString &application)
297
0
{
298
0
    return new QConfFileSettingsPrivate(format, scope, organization, application);
299
0
}
300
#endif
301
302
#if !defined(Q_OS_WIN)
303
QSettingsPrivate *QSettingsPrivate::create(const QString &fileName, QSettings::Format format)
304
0
{
305
0
    return new QConfFileSettingsPrivate(fileName, format);
306
0
}
307
#endif
308
309
void QSettingsPrivate::processChild(QStringRef key, ChildSpec spec, QStringList &result)
310
0
{
311
0
    if (spec != AllKeys) {
312
0
        int slashPos = key.indexOf(QLatin1Char('/'));
313
0
        if (slashPos == -1) {
314
0
            if (spec != ChildKeys)
315
0
                return;
316
0
        } else {
317
0
            if (spec != ChildGroups)
318
0
                return;
319
0
            key.truncate(slashPos);
320
0
        }
321
0
    }
322
0
    result.append(key.toString());
323
0
}
324
325
void QSettingsPrivate::beginGroupOrArray(const QSettingsGroup &group)
326
0
{
327
0
    groupStack.push(group);
328
0
    const QString name = group.name();
329
0
    if (!name.isEmpty())
330
0
        groupPrefix += name + QLatin1Char('/');
331
0
}
332
333
/*
334
    We only set an error if there isn't one set already. This way the user always gets the
335
    first error that occurred. We always allow clearing errors.
336
*/
337
338
void QSettingsPrivate::setStatus(QSettings::Status status) const
339
0
{
340
0
    if (status == QSettings::NoError || this->status == QSettings::NoError)
341
0
        this->status = status;
342
0
}
343
344
void QSettingsPrivate::update()
345
0
{
346
0
    flush();
347
0
    pendingChanges = false;
348
0
}
349
350
void QSettingsPrivate::requestUpdate()
351
0
{
352
0
    if (!pendingChanges) {
353
0
        pendingChanges = true;
354
0
#ifndef QT_NO_QOBJECT
355
0
        Q_Q(QSettings);
356
0
        QCoreApplication::postEvent(q, new QEvent(QEvent::UpdateRequest));
357
#else
358
        update();
359
#endif
360
0
    }
361
0
}
362
363
QStringList QSettingsPrivate::variantListToStringList(const QVariantList &l)
364
0
{
365
0
    QStringList result;
366
0
    result.reserve(l.count());
367
0
    QVariantList::const_iterator it = l.constBegin();
368
0
    for (; it != l.constEnd(); ++it)
369
0
        result.append(variantToString(*it));
370
0
    return result;
371
0
}
372
373
QVariant QSettingsPrivate::stringListToVariantList(const QStringList &l)
374
0
{
375
0
    QStringList outStringList = l;
376
0
    for (int i = 0; i < outStringList.count(); ++i) {
377
0
        const QString &str = outStringList.at(i);
378
379
0
        if (str.startsWith(QLatin1Char('@'))) {
380
0
            if (str.length() >= 2 && str.at(1) == QLatin1Char('@')) {
381
0
                outStringList[i].remove(0, 1);
382
0
            } else {
383
0
                QVariantList variantList;
384
0
                const int stringCount = l.count();
385
0
                variantList.reserve(stringCount);
386
0
                for (int j = 0; j < stringCount; ++j)
387
0
                    variantList.append(stringToVariant(l.at(j)));
388
0
                return variantList;
389
0
            }
390
0
        }
391
0
    }
392
0
    return outStringList;
393
0
}
394
395
QString QSettingsPrivate::variantToString(const QVariant &v)
396
0
{
397
0
    QString result;
398
399
0
    switch (v.userType()) {
400
0
        case QMetaType::UnknownType:
401
0
            result = QLatin1String("@Invalid()");
402
0
            break;
403
404
0
        case QMetaType::QByteArray: {
405
0
            QByteArray a = v.toByteArray();
406
0
            result = QLatin1String("@ByteArray(")
407
0
                     + QLatin1String(a.constData(), a.size())
408
0
                     + QLatin1Char(')');
409
0
            break;
410
0
        }
411
412
0
        case QMetaType::QString:
413
0
        case QMetaType::LongLong:
414
0
        case QMetaType::ULongLong:
415
0
        case QMetaType::Int:
416
0
        case QMetaType::UInt:
417
0
        case QMetaType::Bool:
418
0
        case QMetaType::Double:
419
0
        case QMetaType::QKeySequence: {
420
0
            result = v.toString();
421
0
            if (result.contains(QChar::Null))
422
0
                result = QLatin1String("@String(") + result + QLatin1Char(')');
423
0
            else if (result.startsWith(QLatin1Char('@')))
424
0
                result.prepend(QLatin1Char('@'));
425
0
            break;
426
0
        }
427
0
#ifndef QT_NO_GEOM_VARIANT
428
0
        case QMetaType::QRect: {
429
0
            QRect r = qvariant_cast<QRect>(v);
430
0
            result = QString::asprintf("@Rect(%d %d %d %d)", r.x(), r.y(), r.width(), r.height());
431
0
            break;
432
0
        }
433
0
        case QMetaType::QSize: {
434
0
            QSize s = qvariant_cast<QSize>(v);
435
0
            result = QString::asprintf("@Size(%d %d)", s.width(), s.height());
436
0
            break;
437
0
        }
438
0
        case QMetaType::QPoint: {
439
0
            QPoint p = qvariant_cast<QPoint>(v);
440
0
            result = QString::asprintf("@Point(%d %d)", p.x(), p.y());
441
0
            break;
442
0
        }
443
0
#endif // !QT_NO_GEOM_VARIANT
444
445
0
        default: {
446
0
#ifndef QT_NO_DATASTREAM
447
0
            QDataStream::Version version;
448
0
            const char *typeSpec;
449
0
            if (v.userType() == QMetaType::QDateTime) {
450
0
                version = QDataStream::Qt_5_6;
451
0
                typeSpec = "@DateTime(";
452
0
            } else {
453
0
                version = QDataStream::Qt_4_0;
454
0
                typeSpec = "@Variant(";
455
0
            }
456
0
            QByteArray a;
457
0
            {
458
0
                QDataStream s(&a, QIODevice::WriteOnly);
459
0
                s.setVersion(version);
460
0
                s << v;
461
0
            }
462
463
0
            result = QLatin1String(typeSpec)
464
0
                     + QLatin1String(a.constData(), a.size())
465
0
                     + QLatin1Char(')');
466
#else
467
            Q_ASSERT(!"QSettings: Cannot save custom types without QDataStream support");
468
#endif
469
0
            break;
470
0
        }
471
0
    }
472
473
0
    return result;
474
0
}
475
476
477
QVariant QSettingsPrivate::stringToVariant(const QString &s)
478
0
{
479
0
    if (s.startsWith(QLatin1Char('@'))) {
480
0
        if (s.endsWith(QLatin1Char(')'))) {
481
0
            if (s.startsWith(QLatin1String("@ByteArray("))) {
482
0
                return QVariant(s.midRef(11, s.size() - 12).toLatin1());
483
0
            } else if (s.startsWith(QLatin1String("@String("))) {
484
0
                return QVariant(s.midRef(8, s.size() - 9).toString());
485
0
            } else if (s.startsWith(QLatin1String("@Variant("))
486
0
                       || s.startsWith(QLatin1String("@DateTime("))) {
487
0
#ifndef QT_NO_DATASTREAM
488
0
                QDataStream::Version version;
489
0
                int offset;
490
0
                if (s.at(1) == QLatin1Char('D')) {
491
0
                    version = QDataStream::Qt_5_6;
492
0
                    offset = 10;
493
0
                } else {
494
0
                    version = QDataStream::Qt_4_0;
495
0
                    offset = 9;
496
0
                }
497
0
                QByteArray a = s.midRef(offset).toLatin1();
498
0
                QDataStream stream(&a, QIODevice::ReadOnly);
499
0
                stream.setVersion(version);
500
0
                QVariant result;
501
0
                stream >> result;
502
0
                return result;
503
#else
504
                Q_ASSERT(!"QSettings: Cannot load custom types without QDataStream support");
505
#endif
506
0
#ifndef QT_NO_GEOM_VARIANT
507
0
            } else if (s.startsWith(QLatin1String("@Rect("))) {
508
0
                QStringList args = QSettingsPrivate::splitArgs(s, 5);
509
0
                if (args.size() == 4)
510
0
                    return QVariant(QRect(args[0].toInt(), args[1].toInt(), args[2].toInt(), args[3].toInt()));
511
0
            } else if (s.startsWith(QLatin1String("@Size("))) {
512
0
                QStringList args = QSettingsPrivate::splitArgs(s, 5);
513
0
                if (args.size() == 2)
514
0
                    return QVariant(QSize(args[0].toInt(), args[1].toInt()));
515
0
            } else if (s.startsWith(QLatin1String("@Point("))) {
516
0
                QStringList args = QSettingsPrivate::splitArgs(s, 6);
517
0
                if (args.size() == 2)
518
0
                    return QVariant(QPoint(args[0].toInt(), args[1].toInt()));
519
0
#endif
520
0
            } else if (s == QLatin1String("@Invalid()")) {
521
0
                return QVariant();
522
0
            }
523
524
0
        }
525
0
        if (s.startsWith(QLatin1String("@@")))
526
0
            return QVariant(s.mid(1));
527
0
    }
528
529
0
    return QVariant(s);
530
0
}
531
532
static const char hexDigits[] = "0123456789ABCDEF";
533
534
void QSettingsPrivate::iniEscapedKey(const QString &key, QByteArray &result)
535
0
{
536
0
    result.reserve(result.length() + key.length() * 3 / 2);
537
0
    for (int i = 0; i < key.size(); ++i) {
538
0
        uint ch = key.at(i).unicode();
539
540
0
        if (ch == '/') {
541
0
            result += '\\';
542
0
        } else if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9')
543
0
                || ch == '_' || ch == '-' || ch == '.') {
544
0
            result += (char)ch;
545
0
        } else if (ch <= 0xFF) {
546
0
            result += '%';
547
0
            result += hexDigits[ch / 16];
548
0
            result += hexDigits[ch % 16];
549
0
        } else {
550
0
            result += "%U";
551
0
            QByteArray hexCode;
552
0
            for (int i = 0; i < 4; ++i) {
553
0
                hexCode.prepend(hexDigits[ch % 16]);
554
0
                ch >>= 4;
555
0
            }
556
0
            result += hexCode;
557
0
        }
558
0
    }
559
0
}
560
561
bool QSettingsPrivate::iniUnescapedKey(const QByteArray &key, int from, int to, QString &result)
562
0
{
563
0
    bool lowercaseOnly = true;
564
0
    int i = from;
565
0
    result.reserve(result.length() + (to - from));
566
0
    while (i < to) {
567
0
        int ch = (uchar)key.at(i);
568
569
0
        if (ch == '\\') {
570
0
            result += QLatin1Char('/');
571
0
            ++i;
572
0
            continue;
573
0
        }
574
575
0
        if (ch != '%' || i == to - 1) {
576
0
            if (uint(ch - 'A') <= 'Z' - 'A') // only for ASCII
577
0
                lowercaseOnly = false;
578
0
            result += QLatin1Char(ch);
579
0
            ++i;
580
0
            continue;
581
0
        }
582
583
0
        int numDigits = 2;
584
0
        int firstDigitPos = i + 1;
585
586
0
        ch = key.at(i + 1);
587
0
        if (ch == 'U') {
588
0
            ++firstDigitPos;
589
0
            numDigits = 4;
590
0
        }
591
592
0
        if (firstDigitPos + numDigits > to) {
593
0
            result += QLatin1Char('%');
594
            // ### missing U
595
0
            ++i;
596
0
            continue;
597
0
        }
598
599
0
        bool ok;
600
0
        ch = key.mid(firstDigitPos, numDigits).toInt(&ok, 16);
601
0
        if (!ok) {
602
0
            result += QLatin1Char('%');
603
            // ### missing U
604
0
            ++i;
605
0
            continue;
606
0
        }
607
608
0
        QChar qch(ch);
609
0
        if (qch.isUpper())
610
0
            lowercaseOnly = false;
611
0
        result += qch;
612
0
        i = firstDigitPos + numDigits;
613
0
    }
614
0
    return lowercaseOnly;
615
0
}
616
617
void QSettingsPrivate::iniEscapedString(const QString &str, QByteArray &result, QTextCodec *codec)
618
0
{
619
0
    bool needsQuotes = false;
620
0
    bool escapeNextIfDigit = false;
621
0
    bool useCodec = codec && !str.startsWith(QLatin1String("@ByteArray("))
622
0
                    && !str.startsWith(QLatin1String("@Variant("))
623
0
                    && !str.startsWith(QLatin1String("@DateTime("));
624
625
0
    int i;
626
0
    int startPos = result.size();
627
628
0
    result.reserve(startPos + str.size() * 3 / 2);
629
0
    const QChar *unicode = str.unicode();
630
0
    for (i = 0; i < str.size(); ++i) {
631
0
        uint ch = unicode[i].unicode();
632
0
        if (ch == ';' || ch == ',' || ch == '=')
633
0
            needsQuotes = true;
634
635
0
        if (escapeNextIfDigit
636
0
                && ((ch >= '0' && ch <= '9')
637
0
                    || (ch >= 'a' && ch <= 'f')
638
0
                    || (ch >= 'A' && ch <= 'F'))) {
639
0
            result += "\\x" + QByteArray::number(ch, 16);
640
0
            continue;
641
0
        }
642
643
0
        escapeNextIfDigit = false;
644
645
0
        switch (ch) {
646
0
        case '\0':
647
0
            result += "\\0";
648
0
            escapeNextIfDigit = true;
649
0
            break;
650
0
        case '\a':
651
0
            result += "\\a";
652
0
            break;
653
0
        case '\b':
654
0
            result += "\\b";
655
0
            break;
656
0
        case '\f':
657
0
            result += "\\f";
658
0
            break;
659
0
        case '\n':
660
0
            result += "\\n";
661
0
            break;
662
0
        case '\r':
663
0
            result += "\\r";
664
0
            break;
665
0
        case '\t':
666
0
            result += "\\t";
667
0
            break;
668
0
        case '\v':
669
0
            result += "\\v";
670
0
            break;
671
0
        case '"':
672
0
        case '\\':
673
0
            result += '\\';
674
0
            result += (char)ch;
675
0
            break;
676
0
        default:
677
0
            if (ch <= 0x1F || (ch >= 0x7F && !useCodec)) {
678
0
                result += "\\x" + QByteArray::number(ch, 16);
679
0
                escapeNextIfDigit = true;
680
0
#if QT_CONFIG(textcodec)
681
0
            } else if (useCodec) {
682
                // slow
683
0
                result += codec->fromUnicode(&unicode[i], 1);
684
0
#endif
685
0
            } else {
686
0
                result += (char)ch;
687
0
            }
688
0
        }
689
0
    }
690
691
0
    if (needsQuotes
692
0
            || (startPos < result.size() && (result.at(startPos) == ' '
693
0
                                                || result.at(result.size() - 1) == ' '))) {
694
0
        result.insert(startPos, '"');
695
0
        result += '"';
696
0
    }
697
0
}
698
699
inline static void iniChopTrailingSpaces(QString &str, int limit)
700
0
{
701
0
    int n = str.size() - 1;
702
0
    QChar ch;
703
0
    while (n >= limit && ((ch = str.at(n)) == QLatin1Char(' ') || ch == QLatin1Char('\t')))
704
0
        str.truncate(n--);
705
0
}
706
707
void QSettingsPrivate::iniEscapedStringList(const QStringList &strs, QByteArray &result, QTextCodec *codec)
708
0
{
709
0
    if (strs.isEmpty()) {
710
        /*
711
            We need to distinguish between empty lists and one-item
712
            lists that contain an empty string. Ideally, we'd have a
713
            @EmptyList() symbol but that would break compatibility
714
            with Qt 4.0. @Invalid() stands for QVariant(), and
715
            QVariant().toStringList() returns an empty QStringList,
716
            so we're in good shape.
717
        */
718
0
        result += "@Invalid()";
719
0
    } else {
720
0
        for (int i = 0; i < strs.size(); ++i) {
721
0
            if (i != 0)
722
0
                result += ", ";
723
0
            iniEscapedString(strs.at(i), result, codec);
724
0
        }
725
0
    }
726
0
}
727
728
bool QSettingsPrivate::iniUnescapedStringList(const QByteArray &str, int from, int to,
729
                                              QString &stringResult, QStringList &stringListResult,
730
                                              QTextCodec *codec)
731
0
{
732
0
    static const char escapeCodes[][2] =
733
0
    {
734
0
        { 'a', '\a' },
735
0
        { 'b', '\b' },
736
0
        { 'f', '\f' },
737
0
        { 'n', '\n' },
738
0
        { 'r', '\r' },
739
0
        { 't', '\t' },
740
0
        { 'v', '\v' },
741
0
        { '"', '"' },
742
0
        { '?', '?' },
743
0
        { '\'', '\'' },
744
0
        { '\\', '\\' }
745
0
    };
746
747
0
    bool isStringList = false;
748
0
    bool inQuotedString = false;
749
0
    bool currentValueIsQuoted = false;
750
0
    char16_t escapeVal = 0;
751
0
    int i = from;
752
0
    char ch;
753
754
0
StSkipSpaces:
755
0
    while (i < to && ((ch = str.at(i)) == ' ' || ch == '\t'))
756
0
        ++i;
757
    // fallthrough
758
759
0
StNormal:
760
0
    int chopLimit = stringResult.length();
761
0
    while (i < to) {
762
0
        switch (str.at(i)) {
763
0
        case '\\':
764
0
            ++i;
765
0
            if (i >= to)
766
0
                goto end;
767
768
0
            ch = str.at(i++);
769
0
            for (const auto &escapeCode : escapeCodes) {
770
0
                if (ch == escapeCode[0]) {
771
0
                    stringResult += QLatin1Char(escapeCode[1]);
772
0
                    goto StNormal;
773
0
                }
774
0
            }
775
776
0
            if (ch == 'x') {
777
0
                escapeVal = 0;
778
779
0
                if (i >= to)
780
0
                    goto end;
781
782
0
                ch = str.at(i);
783
0
                if ((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'F') || (ch >= 'a' && ch <= 'f'))
784
0
                    goto StHexEscape;
785
0
            } else if (ch >= '0' && ch <= '7') {
786
0
                escapeVal = ch - '0';
787
0
                goto StOctEscape;
788
0
            } else if (ch == '\n' || ch == '\r') {
789
0
                if (i < to) {
790
0
                    char ch2 = str.at(i);
791
                    // \n, \r, \r\n, and \n\r are legitimate line terminators in INI files
792
0
                    if ((ch2 == '\n' || ch2 == '\r') && ch2 != ch)
793
0
                        ++i;
794
0
                }
795
0
            } else {
796
                // the character is skipped
797
0
            }
798
0
            chopLimit = stringResult.length();
799
0
            break;
800
0
        case '"':
801
0
            ++i;
802
0
            currentValueIsQuoted = true;
803
0
            inQuotedString = !inQuotedString;
804
0
            if (!inQuotedString)
805
0
                goto StSkipSpaces;
806
0
            break;
807
0
        case ',':
808
0
            if (!inQuotedString) {
809
0
                if (!currentValueIsQuoted)
810
0
                    iniChopTrailingSpaces(stringResult, chopLimit);
811
0
                if (!isStringList) {
812
0
                    isStringList = true;
813
0
                    stringListResult.clear();
814
0
                    stringResult.squeeze();
815
0
                }
816
0
                stringListResult.append(stringResult);
817
0
                stringResult.clear();
818
0
                currentValueIsQuoted = false;
819
0
                ++i;
820
0
                goto StSkipSpaces;
821
0
            }
822
0
            Q_FALLTHROUGH();
823
0
        default: {
824
0
            int j = i + 1;
825
0
            while (j < to) {
826
0
                ch = str.at(j);
827
0
                if (ch == '\\' || ch == '"' || ch == ',')
828
0
                    break;
829
0
                ++j;
830
0
            }
831
832
#if !QT_CONFIG(textcodec)
833
            Q_UNUSED(codec)
834
#else
835
0
            if (codec) {
836
0
                stringResult += codec->toUnicode(str.constData() + i, j - i);
837
0
            } else
838
0
#endif
839
0
            {
840
0
                int n = stringResult.size();
841
0
                stringResult.resize(n + (j - i));
842
0
                QChar *resultData = stringResult.data() + n;
843
0
                for (int k = i; k < j; ++k)
844
0
                    *resultData++ = QLatin1Char(str.at(k));
845
0
            }
846
0
            i = j;
847
0
        }
848
0
        }
849
0
    }
850
0
    if (!currentValueIsQuoted)
851
0
        iniChopTrailingSpaces(stringResult, chopLimit);
852
0
    goto end;
853
854
0
StHexEscape:
855
0
    if (i >= to) {
856
0
        stringResult += QChar(escapeVal);
857
0
        goto end;
858
0
    }
859
860
0
    ch = str.at(i);
861
0
    if (ch >= 'a')
862
0
        ch -= 'a' - 'A';
863
0
    if ((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'F')) {
864
0
        escapeVal <<= 4;
865
0
        escapeVal += strchr(hexDigits, ch) - hexDigits;
866
0
        ++i;
867
0
        goto StHexEscape;
868
0
    } else {
869
0
        stringResult += QChar(escapeVal);
870
0
        goto StNormal;
871
0
    }
872
873
0
StOctEscape:
874
0
    if (i >= to) {
875
0
        stringResult += QChar(escapeVal);
876
0
        goto end;
877
0
    }
878
879
0
    ch = str.at(i);
880
0
    if (ch >= '0' && ch <= '7') {
881
0
        escapeVal <<= 3;
882
0
        escapeVal += ch - '0';
883
0
        ++i;
884
0
        goto StOctEscape;
885
0
    } else {
886
0
        stringResult += QChar(escapeVal);
887
0
        goto StNormal;
888
0
    }
889
890
0
end:
891
0
    if (isStringList)
892
0
        stringListResult.append(stringResult);
893
0
    return isStringList;
894
0
}
895
896
QStringList QSettingsPrivate::splitArgs(const QString &s, int idx)
897
0
{
898
0
    int l = s.length();
899
0
    Q_ASSERT(l > 0);
900
0
    Q_ASSERT(s.at(idx) == QLatin1Char('('));
901
0
    Q_ASSERT(s.at(l - 1) == QLatin1Char(')'));
902
903
0
    QStringList result;
904
0
    QString item;
905
906
0
    for (++idx; idx < l; ++idx) {
907
0
        QChar c = s.at(idx);
908
0
        if (c == QLatin1Char(')')) {
909
0
            Q_ASSERT(idx == l - 1);
910
0
            result.append(item);
911
0
        } else if (c == QLatin1Char(' ')) {
912
0
            result.append(item);
913
0
            item.clear();
914
0
        } else {
915
0
            item.append(c);
916
0
        }
917
0
    }
918
919
0
    return result;
920
0
}
921
922
// ************************************************************************
923
// QConfFileSettingsPrivate
924
925
void QConfFileSettingsPrivate::initFormat()
926
0
{
927
0
    extension = (format == QSettings::NativeFormat) ? QLatin1String(".conf") : QLatin1String(".ini");
928
0
    readFunc = nullptr;
929
0
    writeFunc = nullptr;
930
#if defined(Q_OS_MAC)
931
    caseSensitivity = (format == QSettings::NativeFormat) ? Qt::CaseSensitive : IniCaseSensitivity;
932
#else
933
0
    caseSensitivity = IniCaseSensitivity;
934
0
#endif
935
936
0
    if (format > QSettings::IniFormat) {
937
0
        const auto locker = qt_scoped_lock(settingsGlobalMutex);
938
0
        const CustomFormatVector *customFormatVector = customFormatVectorFunc();
939
940
0
        int i = (int)format - (int)QSettings::CustomFormat1;
941
0
        if (i >= 0 && i < customFormatVector->size()) {
942
0
            QConfFileCustomFormat info = customFormatVector->at(i);
943
0
            extension = info.extension;
944
0
            readFunc = info.readFunc;
945
0
            writeFunc = info.writeFunc;
946
0
            caseSensitivity = info.caseSensitivity;
947
0
        }
948
0
    }
949
0
}
950
951
void QConfFileSettingsPrivate::initAccess()
952
0
{
953
0
    if (!confFiles.isEmpty()) {
954
0
        if (format > QSettings::IniFormat) {
955
0
            if (!readFunc)
956
0
                setStatus(QSettings::AccessError);
957
0
        }
958
0
    }
959
960
0
    sync();       // loads the files the first time
961
0
}
962
963
#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
964
static QString windowsConfigPath(const KNOWNFOLDERID &type)
965
{
966
    QString result;
967
968
    PWSTR path = nullptr;
969
    if (SHGetKnownFolderPath(type, KF_FLAG_DONT_VERIFY, NULL, &path) == S_OK) {
970
        result = QString::fromWCharArray(path);
971
        CoTaskMemFree(path);
972
    }
973
974
    if (result.isEmpty()) {
975
        if (type == FOLDERID_ProgramData) {
976
            result = QLatin1String("C:\\temp\\qt-common");
977
        } else if (type == FOLDERID_RoamingAppData) {
978
            result = QLatin1String("C:\\temp\\qt-user");
979
        }
980
    }
981
982
    return result;
983
}
984
#elif defined(Q_OS_WINRT) // Q_OS_WIN && !Q_OS_WINRT
985
986
enum ConfigPathType {
987
    ConfigPath_CommonAppData,
988
    ConfigPath_UserAppData
989
};
990
991
static QString windowsConfigPath(ConfigPathType type)
992
{
993
    static QString result;
994
    while (result.isEmpty()) {
995
        ComPtr<IApplicationDataStatics> applicationDataStatics;
996
        if (FAILED(GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Storage_ApplicationData).Get(), &applicationDataStatics)))
997
            return result;
998
        ComPtr<IApplicationData> applicationData;
999
        if (FAILED(applicationDataStatics->get_Current(&applicationData)))
1000
            return result;
1001
        ComPtr<IStorageFolder> localFolder;
1002
        if (FAILED(applicationData->get_LocalFolder(&localFolder)))
1003
            return result;
1004
        ComPtr<IStorageItem> localFolderItem;
1005
        if (FAILED(localFolder.As(&localFolderItem)))
1006
            return result;
1007
        HString path;
1008
        if (FAILED(localFolderItem->get_Path(path.GetAddressOf())))
1009
            return result;
1010
        result = QString::fromWCharArray(path.GetRawBuffer(nullptr));
1011
    }
1012
1013
    switch (type) {
1014
    case ConfigPath_CommonAppData:
1015
        return result + QLatin1String("\\qt-common");
1016
    case ConfigPath_UserAppData:
1017
        return result + QLatin1String("\\qt-user");
1018
    }
1019
    return result;
1020
}
1021
#endif // Q_OS_WINRT
1022
1023
static inline int pathHashKey(QSettings::Format format, QSettings::Scope scope)
1024
0
{
1025
0
    return int((uint(format) << 1) | uint(scope == QSettings::SystemScope));
1026
0
}
1027
1028
#ifndef Q_OS_WIN
1029
static QString make_user_path()
1030
0
{
1031
0
    static Q_CONSTEXPR QChar sep = QLatin1Char('/');
1032
#ifndef QSETTINGS_USE_QSTANDARDPATHS
1033
    // Non XDG platforms (OS X, iOS, Android...) have used this code path erroneously
1034
    // for some time now. Moving away from that would require migrating existing settings.
1035
    QByteArray env = qgetenv("XDG_CONFIG_HOME");
1036
    if (env.isEmpty()) {
1037
        return QDir::homePath() + QLatin1String("/.config/");
1038
    } else if (env.startsWith('/')) {
1039
        return QFile::decodeName(env) + sep;
1040
    } else {
1041
        return QDir::homePath() + sep + QFile::decodeName(env) + sep;
1042
    }
1043
#else
1044
    // When using a proper XDG platform, use QStandardPaths rather than the above hand-written code;
1045
    // it makes the use of test mode from unit tests possible.
1046
    // Ideally all platforms should use this, but see above for the migration issue.
1047
0
    return QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + sep;
1048
0
#endif
1049
0
}
1050
#endif // !Q_OS_WIN
1051
1052
static std::unique_lock<QBasicMutex> initDefaultPaths(std::unique_lock<QBasicMutex> locker)
1053
0
{
1054
0
    PathHash *pathHash = pathHashFunc();
1055
1056
0
    locker.unlock();
1057
1058
    /*
1059
       QLibraryInfo::location() uses QSettings, so in order to
1060
       avoid a dead-lock, we can't hold the global mutex while
1061
       calling it.
1062
    */
1063
0
    QString systemPath = QLibraryInfo::location(QLibraryInfo::SettingsPath) + QLatin1Char('/');
1064
1065
0
    locker.lock();
1066
0
    if (pathHash->isEmpty()) {
1067
        /*
1068
           Lazy initialization of pathHash. We initialize the
1069
           IniFormat paths and (on Unix) the NativeFormat paths.
1070
           (The NativeFormat paths are not configurable for the
1071
           Windows registry and the Mac CFPreferences.)
1072
       */
1073
#ifdef Q_OS_WIN
1074
1075
#  ifdef Q_OS_WINRT
1076
        const QString roamingAppDataFolder = windowsConfigPath(ConfigPath_UserAppData);
1077
        const QString programDataFolder = windowsConfigPath(ConfigPath_CommonAppData);
1078
#  else
1079
        const QString roamingAppDataFolder = windowsConfigPath(FOLDERID_RoamingAppData);
1080
        const QString programDataFolder = windowsConfigPath(FOLDERID_ProgramData);
1081
#  endif
1082
        pathHash->insert(pathHashKey(QSettings::IniFormat, QSettings::UserScope),
1083
                         Path(roamingAppDataFolder + QDir::separator(), false));
1084
        pathHash->insert(pathHashKey(QSettings::IniFormat, QSettings::SystemScope),
1085
                         Path(programDataFolder + QDir::separator(), false));
1086
#else
1087
0
        const QString userPath = make_user_path();
1088
0
        pathHash->insert(pathHashKey(QSettings::IniFormat, QSettings::UserScope), Path(userPath, false));
1089
0
        pathHash->insert(pathHashKey(QSettings::IniFormat, QSettings::SystemScope), Path(systemPath, false));
1090
0
#ifndef Q_OS_MAC
1091
0
        pathHash->insert(pathHashKey(QSettings::NativeFormat, QSettings::UserScope), Path(userPath, false));
1092
0
        pathHash->insert(pathHashKey(QSettings::NativeFormat, QSettings::SystemScope), Path(systemPath, false));
1093
0
#endif
1094
0
#endif // Q_OS_WIN
1095
0
    }
1096
1097
0
    return locker;
1098
0
}
1099
1100
static Path getPath(QSettings::Format format, QSettings::Scope scope)
1101
0
{
1102
0
    Q_ASSERT((int)QSettings::NativeFormat == 0);
1103
0
    Q_ASSERT((int)QSettings::IniFormat == 1);
1104
1105
0
    auto locker = qt_unique_lock(settingsGlobalMutex);
1106
0
    PathHash *pathHash = pathHashFunc();
1107
0
    if (pathHash->isEmpty())
1108
0
        locker = initDefaultPaths(std::move(locker));
1109
1110
0
    Path result = pathHash->value(pathHashKey(format, scope));
1111
0
    if (!result.path.isEmpty())
1112
0
        return result;
1113
1114
    // fall back on INI path
1115
0
    return pathHash->value(pathHashKey(QSettings::IniFormat, scope));
1116
0
}
1117
1118
#if defined(QT_BUILD_INTERNAL) && defined(Q_XDG_PLATFORM) && !defined(QT_NO_STANDARDPATHS)
1119
// Note: Suitable only for autotests.
1120
void Q_AUTOTEST_EXPORT clearDefaultPaths()
1121
{
1122
    const auto locker = qt_scoped_lock(settingsGlobalMutex);
1123
    pathHashFunc()->clear();
1124
}
1125
#endif // QT_BUILD_INTERNAL && Q_XDG_PLATFORM && !QT_NO_STANDARDPATHS
1126
1127
QConfFileSettingsPrivate::QConfFileSettingsPrivate(QSettings::Format format,
1128
                                                   QSettings::Scope scope,
1129
                                                   const QString &organization,
1130
                                                   const QString &application)
1131
    : QSettingsPrivate(format, scope, organization, application),
1132
      nextPosition(0x40000000) // big positive number
1133
0
{
1134
0
    initFormat();
1135
1136
0
    QString org = organization;
1137
0
    if (org.isEmpty()) {
1138
0
        setStatus(QSettings::AccessError);
1139
0
        org = QLatin1String("Unknown Organization");
1140
0
    }
1141
1142
0
    QString appFile = org + QDir::separator() + application + extension;
1143
0
    QString orgFile = org + extension;
1144
1145
0
    if (scope == QSettings::UserScope) {
1146
0
        Path userPath = getPath(format, QSettings::UserScope);
1147
0
        if (!application.isEmpty())
1148
0
            confFiles.append(QConfFile::fromName(userPath.path + appFile, true));
1149
0
        confFiles.append(QConfFile::fromName(userPath.path + orgFile, true));
1150
0
    }
1151
1152
0
    Path systemPath = getPath(format, QSettings::SystemScope);
1153
0
#if defined(Q_XDG_PLATFORM) && !defined(QT_NO_STANDARDPATHS)
1154
    // check if the systemPath wasn't overridden by QSettings::setPath()
1155
0
    if (!systemPath.userDefined) {
1156
        // Note: We can't use QStandardPaths::locateAll() as we need all the
1157
        // possible files (not just the existing ones) and there is no way
1158
        // to exclude user specific (XDG_CONFIG_HOME) directory from the search.
1159
0
        QStringList dirs = QStandardPaths::standardLocations(QStandardPaths::GenericConfigLocation);
1160
        // remove the QStandardLocation::writableLocation() (XDG_CONFIG_HOME)
1161
0
        if (!dirs.isEmpty())
1162
0
            dirs.takeFirst();
1163
0
        QStringList paths;
1164
0
        if (!application.isEmpty()) {
1165
0
            paths.reserve(dirs.size() * 2);
1166
0
            for (const auto &dir : qAsConst(dirs))
1167
0
                paths.append(dir + QLatin1Char('/') + appFile);
1168
0
        } else {
1169
0
            paths.reserve(dirs.size());
1170
0
        }
1171
0
        for (const auto &dir : qAsConst(dirs))
1172
0
            paths.append(dir + QLatin1Char('/') + orgFile);
1173
1174
        // Note: No check for existence of files is done intentionaly.
1175
0
        for (const auto &path : qAsConst(paths))
1176
0
            confFiles.append(QConfFile::fromName(path, false));
1177
0
    } else
1178
0
#endif // Q_XDG_PLATFORM && !QT_NO_STANDARDPATHS
1179
0
    {
1180
0
        if (!application.isEmpty())
1181
0
            confFiles.append(QConfFile::fromName(systemPath.path + appFile, false));
1182
0
        confFiles.append(QConfFile::fromName(systemPath.path + orgFile, false));
1183
0
    }
1184
1185
0
#ifndef Q_OS_WASM // wasm needs to delay access until after file sync
1186
0
    initAccess();
1187
0
#endif
1188
0
}
1189
1190
QConfFileSettingsPrivate::QConfFileSettingsPrivate(const QString &fileName,
1191
                                                   QSettings::Format format)
1192
    : QSettingsPrivate(format),
1193
      nextPosition(0x40000000) // big positive number
1194
0
{
1195
0
    initFormat();
1196
1197
0
    confFiles.append(QConfFile::fromName(fileName, true));
1198
1199
0
    initAccess();
1200
0
}
1201
1202
QConfFileSettingsPrivate::~QConfFileSettingsPrivate()
1203
0
{
1204
0
    const auto locker = qt_scoped_lock(settingsGlobalMutex);
1205
0
    ConfFileHash *usedHash = usedHashFunc();
1206
0
    ConfFileCache *unusedCache = unusedCacheFunc();
1207
1208
0
    for (auto conf_file : qAsConst(confFiles)) {
1209
0
        if (!conf_file->ref.deref()) {
1210
0
            if (conf_file->size == 0) {
1211
0
                delete conf_file;
1212
0
            } else {
1213
0
                if (usedHash)
1214
0
                    usedHash->remove(conf_file->name);
1215
0
                if (unusedCache) {
1216
0
                    QT_TRY {
1217
                        // compute a better size?
1218
0
                        unusedCache->insert(conf_file->name, conf_file,
1219
0
                                            10 + (conf_file->originalKeys.size() / 4));
1220
0
                    } QT_CATCH(...) {
1221
                        // out of memory. Do not cache the file.
1222
0
                        delete conf_file;
1223
0
                    }
1224
0
                } else {
1225
                    // unusedCache is gone - delete the entry to prevent a memory leak
1226
0
                    delete conf_file;
1227
0
                }
1228
0
            }
1229
0
        }
1230
0
    }
1231
0
}
1232
1233
void QConfFileSettingsPrivate::remove(const QString &key)
1234
0
{
1235
0
    if (confFiles.isEmpty())
1236
0
        return;
1237
1238
    // Note: First config file is always the most specific.
1239
0
    QConfFile *confFile = confFiles.at(0);
1240
1241
0
    QSettingsKey theKey(key, caseSensitivity);
1242
0
    QSettingsKey prefix(key + QLatin1Char('/'), caseSensitivity);
1243
0
    const auto locker = qt_scoped_lock(confFile->mutex);
1244
1245
0
    ensureSectionParsed(confFile, theKey);
1246
0
    ensureSectionParsed(confFile, prefix);
1247
1248
0
    ParsedSettingsMap::iterator i = confFile->addedKeys.lowerBound(prefix);
1249
0
    while (i != confFile->addedKeys.end() && i.key().startsWith(prefix))
1250
0
        i = confFile->addedKeys.erase(i);
1251
0
    confFile->addedKeys.remove(theKey);
1252
1253
0
    ParsedSettingsMap::const_iterator j = const_cast<const ParsedSettingsMap *>(&confFile->originalKeys)->lowerBound(prefix);
1254
0
    while (j != confFile->originalKeys.constEnd() && j.key().startsWith(prefix)) {
1255
0
        confFile->removedKeys.insert(j.key(), QVariant());
1256
0
        ++j;
1257
0
    }
1258
0
    if (confFile->originalKeys.contains(theKey))
1259
0
        confFile->removedKeys.insert(theKey, QVariant());
1260
0
}
1261
1262
void QConfFileSettingsPrivate::set(const QString &key, const QVariant &value)
1263
0
{
1264
0
    if (confFiles.isEmpty())
1265
0
        return;
1266
1267
    // Note: First config file is always the most specific.
1268
0
    QConfFile *confFile = confFiles.at(0);
1269
1270
0
    QSettingsKey theKey(key, caseSensitivity, nextPosition++);
1271
0
    const auto locker = qt_scoped_lock(confFile->mutex);
1272
0
    confFile->removedKeys.remove(theKey);
1273
0
    confFile->addedKeys.insert(theKey, value);
1274
0
}
1275
1276
bool QConfFileSettingsPrivate::get(const QString &key, QVariant *value) const
1277
0
{
1278
0
    QSettingsKey theKey(key, caseSensitivity);
1279
0
    ParsedSettingsMap::const_iterator j;
1280
0
    bool found = false;
1281
1282
0
    for (auto confFile : qAsConst(confFiles)) {
1283
0
        const auto locker = qt_scoped_lock(confFile->mutex);
1284
1285
0
        if (!confFile->addedKeys.isEmpty()) {
1286
0
            j = confFile->addedKeys.constFind(theKey);
1287
0
            found = (j != confFile->addedKeys.constEnd());
1288
0
        }
1289
0
        if (!found) {
1290
0
            ensureSectionParsed(confFile, theKey);
1291
0
            j = confFile->originalKeys.constFind(theKey);
1292
0
            found = (j != confFile->originalKeys.constEnd()
1293
0
                     && !confFile->removedKeys.contains(theKey));
1294
0
        }
1295
1296
0
        if (found && value)
1297
0
            *value = *j;
1298
1299
0
        if (found)
1300
0
            return true;
1301
0
        if (!fallbacks)
1302
0
            break;
1303
0
    }
1304
0
    return false;
1305
0
}
1306
1307
QStringList QConfFileSettingsPrivate::children(const QString &prefix, ChildSpec spec) const
1308
0
{
1309
0
    QStringList result;
1310
0
    ParsedSettingsMap::const_iterator j;
1311
1312
0
    QSettingsKey thePrefix(prefix, caseSensitivity);
1313
0
    int startPos = prefix.size();
1314
1315
0
    for (auto confFile : qAsConst(confFiles)) {
1316
0
        const auto locker = qt_scoped_lock(confFile->mutex);
1317
1318
0
        if (thePrefix.isEmpty())
1319
0
            ensureAllSectionsParsed(confFile);
1320
0
        else
1321
0
            ensureSectionParsed(confFile, thePrefix);
1322
1323
0
        j = const_cast<const ParsedSettingsMap *>(
1324
0
                &confFile->originalKeys)->lowerBound( thePrefix);
1325
0
        while (j != confFile->originalKeys.constEnd() && j.key().startsWith(thePrefix)) {
1326
0
            if (!confFile->removedKeys.contains(j.key()))
1327
0
                processChild(j.key().originalCaseKey().midRef(startPos), spec, result);
1328
0
            ++j;
1329
0
        }
1330
1331
0
        j = const_cast<const ParsedSettingsMap *>(
1332
0
                &confFile->addedKeys)->lowerBound(thePrefix);
1333
0
        while (j != confFile->addedKeys.constEnd() && j.key().startsWith(thePrefix)) {
1334
0
            processChild(j.key().originalCaseKey().midRef(startPos), spec, result);
1335
0
            ++j;
1336
0
        }
1337
1338
0
        if (!fallbacks)
1339
0
            break;
1340
0
    }
1341
0
    std::sort(result.begin(), result.end());
1342
0
    result.erase(std::unique(result.begin(), result.end()),
1343
0
                 result.end());
1344
0
    return result;
1345
0
}
1346
1347
void QConfFileSettingsPrivate::clear()
1348
0
{
1349
0
    if (confFiles.isEmpty())
1350
0
        return;
1351
1352
    // Note: First config file is always the most specific.
1353
0
    QConfFile *confFile = confFiles.at(0);
1354
1355
0
    const auto locker = qt_scoped_lock(confFile->mutex);
1356
0
    ensureAllSectionsParsed(confFile);
1357
0
    confFile->addedKeys.clear();
1358
0
    confFile->removedKeys = confFile->originalKeys;
1359
0
}
1360
1361
void QConfFileSettingsPrivate::sync()
1362
0
{
1363
    // people probably won't be checking the status a whole lot, so in case of
1364
    // error we just try to go on and make the best of it
1365
1366
0
    for (auto confFile : qAsConst(confFiles)) {
1367
0
        const auto locker = qt_scoped_lock(confFile->mutex);
1368
0
        syncConfFile(confFile);
1369
0
    }
1370
0
}
1371
1372
void QConfFileSettingsPrivate::flush()
1373
0
{
1374
0
    sync();
1375
0
}
1376
1377
QString QConfFileSettingsPrivate::fileName() const
1378
0
{
1379
0
    if (confFiles.isEmpty())
1380
0
        return QString();
1381
1382
    // Note: First config file is always the most specific.
1383
0
    return confFiles.at(0)->name;
1384
0
}
1385
1386
bool QConfFileSettingsPrivate::isWritable() const
1387
0
{
1388
0
    if (format > QSettings::IniFormat && !writeFunc)
1389
0
        return false;
1390
1391
0
    if (confFiles.isEmpty())
1392
0
        return false;
1393
1394
0
    return confFiles.at(0)->isWritable();
1395
0
}
1396
1397
void QConfFileSettingsPrivate::syncConfFile(QConfFile *confFile)
1398
0
{
1399
0
    bool readOnly = confFile->addedKeys.isEmpty() && confFile->removedKeys.isEmpty();
1400
1401
    /*
1402
        We can often optimize the read-only case, if the file on disk
1403
        hasn't changed.
1404
    */
1405
0
    if (readOnly && confFile->size > 0) {
1406
0
        QFileInfo fileInfo(confFile->name);
1407
0
        if (confFile->size == fileInfo.size() && confFile->timeStamp == fileInfo.lastModified())
1408
0
            return;
1409
0
    }
1410
1411
0
    if (!readOnly && !confFile->isWritable()) {
1412
0
        setStatus(QSettings::AccessError);
1413
0
        return;
1414
0
    }
1415
1416
0
#ifndef QT_BOOTSTRAPPED
1417
    /*
1418
        Use a lockfile in order to protect us against other QSettings instances
1419
        trying to write the same settings at the same time.
1420
1421
        We only need to lock if we are actually writing as only concurrent writes are a problem.
1422
        Concurrent read and write are not a problem because the writing operation is atomic.
1423
    */
1424
0
    QLockFile lockFile(confFile->name + QLatin1String(".lock"));
1425
0
    if (!readOnly && !lockFile.lock() && atomicSyncOnly) {
1426
0
        setStatus(QSettings::AccessError);
1427
0
        return;
1428
0
    }
1429
0
#endif
1430
1431
    /*
1432
        We hold the lock. Let's reread the file if it has changed
1433
        since last time we read it.
1434
    */
1435
0
    QFileInfo fileInfo(confFile->name);
1436
0
    bool mustReadFile = true;
1437
0
    bool createFile = !fileInfo.exists();
1438
1439
0
    if (!readOnly)
1440
0
        mustReadFile = (confFile->size != fileInfo.size()
1441
0
                        || (confFile->size != 0 && confFile->timeStamp != fileInfo.lastModified()));
1442
1443
0
    if (mustReadFile) {
1444
0
        confFile->unparsedIniSections.clear();
1445
0
        confFile->originalKeys.clear();
1446
1447
0
        QFile file(confFile->name);
1448
0
        if (!createFile && !file.open(QFile::ReadOnly)) {
1449
0
            setStatus(QSettings::AccessError);
1450
0
            return;
1451
0
        }
1452
1453
        /*
1454
            Files that we can't read (because of permissions or
1455
            because they don't exist) are treated as empty files.
1456
        */
1457
0
        if (file.isReadable() && file.size() != 0) {
1458
0
            bool ok = false;
1459
#ifdef Q_OS_MAC
1460
            if (format == QSettings::NativeFormat) {
1461
                QByteArray data = file.readAll();
1462
                ok = readPlistFile(data, &confFile->originalKeys);
1463
            } else
1464
#endif
1465
0
            if (format <= QSettings::IniFormat) {
1466
0
                QByteArray data = file.readAll();
1467
0
                ok = readIniFile(data, &confFile->unparsedIniSections);
1468
0
            } else if (readFunc) {
1469
0
                QSettings::SettingsMap tempNewKeys;
1470
0
                ok = readFunc(file, tempNewKeys);
1471
1472
0
                if (ok) {
1473
0
                    QSettings::SettingsMap::const_iterator i = tempNewKeys.constBegin();
1474
0
                    while (i != tempNewKeys.constEnd()) {
1475
0
                        confFile->originalKeys.insert(QSettingsKey(i.key(), caseSensitivity),
1476
0
                                                      i.value());
1477
0
                        ++i;
1478
0
                    }
1479
0
                }
1480
0
            }
1481
1482
0
            if (!ok)
1483
0
                setStatus(QSettings::FormatError);
1484
0
        }
1485
1486
0
        confFile->size = fileInfo.size();
1487
0
        confFile->timeStamp = fileInfo.lastModified();
1488
0
    }
1489
1490
    /*
1491
        We also need to save the file. We still hold the file lock,
1492
        so everything is under control.
1493
    */
1494
0
    if (!readOnly) {
1495
0
        bool ok = false;
1496
0
        ensureAllSectionsParsed(confFile);
1497
0
        ParsedSettingsMap mergedKeys = confFile->mergedKeyMap();
1498
1499
0
#if !defined(QT_BOOTSTRAPPED) && QT_CONFIG(temporaryfile)
1500
0
        QSaveFile sf(confFile->name);
1501
0
        sf.setDirectWriteFallback(!atomicSyncOnly);
1502
#else
1503
        QFile sf(confFile->name);
1504
#endif
1505
0
        if (!sf.open(QIODevice::WriteOnly)) {
1506
0
            setStatus(QSettings::AccessError);
1507
0
            return;
1508
0
        }
1509
1510
#ifdef Q_OS_MAC
1511
        if (format == QSettings::NativeFormat) {
1512
            ok = writePlistFile(sf, mergedKeys);
1513
        } else
1514
#endif
1515
0
        if (format <= QSettings::IniFormat) {
1516
0
            ok = writeIniFile(sf, mergedKeys);
1517
0
        } else if (writeFunc) {
1518
0
            QSettings::SettingsMap tempOriginalKeys;
1519
1520
0
            ParsedSettingsMap::const_iterator i = mergedKeys.constBegin();
1521
0
            while (i != mergedKeys.constEnd()) {
1522
0
                tempOriginalKeys.insert(i.key(), i.value());
1523
0
                ++i;
1524
0
            }
1525
0
            ok = writeFunc(sf, tempOriginalKeys);
1526
0
        }
1527
1528
0
#if !defined(QT_BOOTSTRAPPED) && QT_CONFIG(temporaryfile)
1529
0
        if (ok)
1530
0
            ok = sf.commit();
1531
0
#endif
1532
1533
0
        if (ok) {
1534
0
            confFile->unparsedIniSections.clear();
1535
0
            confFile->originalKeys = mergedKeys;
1536
0
            confFile->addedKeys.clear();
1537
0
            confFile->removedKeys.clear();
1538
1539
0
            QFileInfo fileInfo(confFile->name);
1540
0
            confFile->size = fileInfo.size();
1541
0
            confFile->timeStamp = fileInfo.lastModified();
1542
1543
            // If we have created the file, apply the file perms
1544
0
            if (createFile) {
1545
0
                QFile::Permissions perms = fileInfo.permissions() | QFile::ReadOwner | QFile::WriteOwner;
1546
0
                if (!confFile->userPerms)
1547
0
                    perms |= QFile::ReadGroup | QFile::ReadOther;
1548
0
                QFile(confFile->name).setPermissions(perms);
1549
0
            }
1550
0
        } else {
1551
0
            setStatus(QSettings::AccessError);
1552
0
        }
1553
0
    }
1554
0
}
1555
1556
enum { Space = 0x1, Special = 0x2 };
1557
1558
static const char charTraits[256] =
1559
{
1560
    // Space: '\t', '\n', '\r', ' '
1561
    // Special: '\n', '\r', '"', ';', '=', '\\'
1562
1563
    0, 0, 0, 0, 0, 0, 0, 0, 0, Space, Space | Special, 0, 0, Space | Special, 0, 0,
1564
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1565
    Space, 0, Special, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1566
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Special, 0, Special, 0, 0,
1567
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1568
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Special, 0, 0, 0,
1569
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1570
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1571
1572
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1573
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1574
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1575
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1576
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1577
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1578
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1579
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
1580
};
1581
1582
bool QConfFileSettingsPrivate::readIniLine(const QByteArray &data, int &dataPos,
1583
                                           int &lineStart, int &lineLen, int &equalsPos)
1584
0
{
1585
0
    int dataLen = data.length();
1586
0
    bool inQuotes = false;
1587
1588
0
    equalsPos = -1;
1589
1590
0
    lineStart = dataPos;
1591
0
    while (lineStart < dataLen && (charTraits[uint(uchar(data.at(lineStart)))] & Space))
1592
0
        ++lineStart;
1593
1594
0
    int i = lineStart;
1595
0
    while (i < dataLen) {
1596
0
        char ch = data.at(i);
1597
0
        while (!(charTraits[uchar(ch)] & Special)) {
1598
0
            if (++i == dataLen)
1599
0
                goto break_out_of_outer_loop;
1600
0
            ch = data.at(i);
1601
0
        }
1602
1603
0
        ++i;
1604
0
        if (ch == '=') {
1605
0
            if (!inQuotes && equalsPos == -1)
1606
0
                equalsPos = i - 1;
1607
0
        } else if (ch == '\n' || ch == '\r') {
1608
0
            if (i == lineStart + 1) {
1609
0
                ++lineStart;
1610
0
            } else if (!inQuotes) {
1611
0
                --i;
1612
0
                goto break_out_of_outer_loop;
1613
0
            }
1614
0
        } else if (ch == '\\') {
1615
0
            if (i < dataLen) {
1616
0
                char ch = data.at(i++);
1617
0
                if (i < dataLen) {
1618
0
                    char ch2 = data.at(i);
1619
                    // \n, \r, \r\n, and \n\r are legitimate line terminators in INI files
1620
0
                    if ((ch == '\n' && ch2 == '\r') || (ch == '\r' && ch2 == '\n'))
1621
0
                        ++i;
1622
0
                }
1623
0
            }
1624
0
        } else if (ch == '"') {
1625
0
            inQuotes = !inQuotes;
1626
0
        } else {
1627
0
            Q_ASSERT(ch == ';');
1628
1629
0
            if (i == lineStart + 1) {
1630
0
                while (i < dataLen && (((ch = data.at(i)) != '\n') && ch != '\r'))
1631
0
                    ++i;
1632
0
                while (i < dataLen && charTraits[uchar(data.at(i))] & Space)
1633
0
                    ++i;
1634
0
                lineStart = i;
1635
0
            } else if (!inQuotes) {
1636
0
                --i;
1637
0
                goto break_out_of_outer_loop;
1638
0
            }
1639
0
        }
1640
0
    }
1641
1642
0
break_out_of_outer_loop:
1643
0
    dataPos = i;
1644
0
    lineLen = i - lineStart;
1645
0
    return lineLen > 0;
1646
0
}
1647
1648
/*
1649
    Returns \c false on parse error. However, as many keys are read as
1650
    possible, so if the user doesn't check the status he will get the
1651
    most out of the file anyway.
1652
*/
1653
bool QConfFileSettingsPrivate::readIniFile(const QByteArray &data,
1654
                                           UnparsedSettingsMap *unparsedIniSections)
1655
0
{
1656
0
#define FLUSH_CURRENT_SECTION() \
1657
0
    { \
1658
0
        QByteArray &sectionData = (*unparsedIniSections)[QSettingsKey(currentSection, \
1659
0
                                                                      IniCaseSensitivity, \
1660
0
                                                                      sectionPosition)]; \
1661
0
        if (!sectionData.isEmpty()) \
1662
0
            sectionData.append('\n'); \
1663
0
        sectionData += data.mid(currentSectionStart, lineStart - currentSectionStart); \
1664
0
        sectionPosition = ++position; \
1665
0
    }
1666
1667
0
    QString currentSection;
1668
0
    int currentSectionStart = 0;
1669
0
    int dataPos = 0;
1670
0
    int lineStart;
1671
0
    int lineLen;
1672
0
    int equalsPos;
1673
0
    int position = 0;
1674
0
    int sectionPosition = 0;
1675
0
    bool ok = true;
1676
1677
    // detect utf8 BOM
1678
0
    const uchar *dd = (const uchar *)data.constData();
1679
0
    if (data.size() >= 3 && dd[0] == 0xef && dd[1] == 0xbb && dd[2] == 0xbf) {
1680
0
#if QT_CONFIG(textcodec)
1681
0
        iniCodec = QTextCodec::codecForName("UTF-8");
1682
#else
1683
        ok = false;
1684
#endif
1685
0
        dataPos = 3;
1686
0
    }
1687
1688
0
    while (readIniLine(data, dataPos, lineStart, lineLen, equalsPos)) {
1689
0
        char ch = data.at(lineStart);
1690
0
        if (ch == '[') {
1691
0
            FLUSH_CURRENT_SECTION();
1692
1693
            // this is a section
1694
0
            QByteArray iniSection;
1695
0
            int idx = data.indexOf(']', lineStart);
1696
0
            if (idx == -1 || idx >= lineStart + lineLen) {
1697
0
                ok = false;
1698
0
                iniSection = data.mid(lineStart + 1, lineLen - 1);
1699
0
            } else {
1700
0
                iniSection = data.mid(lineStart + 1, idx - lineStart - 1);
1701
0
            }
1702
1703
0
            iniSection = iniSection.trimmed();
1704
1705
0
            if (iniSection.compare("general", Qt::CaseInsensitive) == 0) {
1706
0
                currentSection.clear();
1707
0
            } else {
1708
0
                if (iniSection.compare("%general", Qt::CaseInsensitive) == 0) {
1709
0
                    currentSection = QLatin1String(iniSection.constData() + 1);
1710
0
                } else {
1711
0
                    currentSection.clear();
1712
0
                    iniUnescapedKey(iniSection, 0, iniSection.size(), currentSection);
1713
0
                }
1714
0
                currentSection += QLatin1Char('/');
1715
0
            }
1716
0
            currentSectionStart = dataPos;
1717
0
        }
1718
0
        ++position;
1719
0
    }
1720
1721
0
    Q_ASSERT(lineStart == data.length());
1722
0
    FLUSH_CURRENT_SECTION();
1723
1724
0
    return ok;
1725
1726
0
#undef FLUSH_CURRENT_SECTION
1727
0
}
1728
1729
bool QConfFileSettingsPrivate::readIniSection(const QSettingsKey &section, const QByteArray &data,
1730
                                              ParsedSettingsMap *settingsMap, QTextCodec *codec)
1731
0
{
1732
0
    QStringList strListValue;
1733
0
    bool sectionIsLowercase = (section == section.originalCaseKey());
1734
0
    int equalsPos;
1735
1736
0
    bool ok = true;
1737
0
    int dataPos = 0;
1738
0
    int lineStart;
1739
0
    int lineLen;
1740
0
    int position = section.originalKeyPosition();
1741
1742
0
    while (readIniLine(data, dataPos, lineStart, lineLen, equalsPos)) {
1743
0
        char ch = data.at(lineStart);
1744
0
        Q_ASSERT(ch != '[');
1745
1746
0
        if (equalsPos == -1) {
1747
0
            if (ch != ';')
1748
0
                ok = false;
1749
0
            continue;
1750
0
        }
1751
1752
0
        int keyEnd = equalsPos;
1753
0
        while (keyEnd > lineStart && ((ch = data.at(keyEnd - 1)) == ' ' || ch == '\t'))
1754
0
            --keyEnd;
1755
0
        int valueStart = equalsPos + 1;
1756
1757
0
        QString key = section.originalCaseKey();
1758
0
        bool keyIsLowercase = (iniUnescapedKey(data, lineStart, keyEnd, key) && sectionIsLowercase);
1759
1760
0
        QString strValue;
1761
0
        strValue.reserve(lineLen - (valueStart - lineStart));
1762
0
        bool isStringList = iniUnescapedStringList(data, valueStart, lineStart + lineLen,
1763
0
                                                   strValue, strListValue, codec);
1764
0
        QVariant variant;
1765
0
        if (isStringList) {
1766
0
            variant = stringListToVariantList(strListValue);
1767
0
        } else {
1768
0
            variant = stringToVariant(strValue);
1769
0
        }
1770
1771
        /*
1772
            We try to avoid the expensive toLower() call in
1773
            QSettingsKey by passing Qt::CaseSensitive when the
1774
            key is already in lowercase.
1775
        */
1776
0
        settingsMap->insert(QSettingsKey(key, keyIsLowercase ? Qt::CaseSensitive
1777
0
                                                             : IniCaseSensitivity,
1778
0
                                         position),
1779
0
                            variant);
1780
0
        ++position;
1781
0
    }
1782
1783
0
    return ok;
1784
0
}
1785
1786
class QSettingsIniKey : public QString
1787
{
1788
public:
1789
0
    inline QSettingsIniKey() : position(-1) {}
1790
0
    inline QSettingsIniKey(const QString &str, int pos = -1) : QString(str), position(pos) {}
1791
1792
    int position;
1793
};
1794
Q_DECLARE_TYPEINFO(QSettingsIniKey, Q_MOVABLE_TYPE);
1795
1796
static bool operator<(const QSettingsIniKey &k1, const QSettingsIniKey &k2)
1797
0
{
1798
0
    if (k1.position != k2.position)
1799
0
        return k1.position < k2.position;
1800
0
    return static_cast<const QString &>(k1) < static_cast<const QString &>(k2);
1801
0
}
1802
1803
typedef QMap<QSettingsIniKey, QVariant> IniKeyMap;
1804
1805
struct QSettingsIniSection
1806
{
1807
    int position;
1808
    IniKeyMap keyMap;
1809
1810
0
    inline QSettingsIniSection() : position(-1) {}
1811
};
1812
1813
Q_DECLARE_TYPEINFO(QSettingsIniSection, Q_MOVABLE_TYPE);
1814
1815
typedef QMap<QString, QSettingsIniSection> IniMap;
1816
1817
/*
1818
    This would be more straightforward if we didn't try to remember the original
1819
    key order in the .ini file, but we do.
1820
*/
1821
bool QConfFileSettingsPrivate::writeIniFile(QIODevice &device, const ParsedSettingsMap &map)
1822
0
{
1823
0
    IniMap iniMap;
1824
0
    IniMap::const_iterator i;
1825
1826
#ifdef Q_OS_WIN
1827
    const char * const eol = "\r\n";
1828
#else
1829
0
    const char eol = '\n';
1830
0
#endif
1831
1832
0
    for (ParsedSettingsMap::const_iterator j = map.constBegin(); j != map.constEnd(); ++j) {
1833
0
        QString section;
1834
0
        QSettingsIniKey key(j.key().originalCaseKey(), j.key().originalKeyPosition());
1835
0
        int slashPos;
1836
1837
0
        if ((slashPos = key.indexOf(QLatin1Char('/'))) != -1) {
1838
0
            section = key.left(slashPos);
1839
0
            key.remove(0, slashPos + 1);
1840
0
        }
1841
1842
0
        QSettingsIniSection &iniSection = iniMap[section];
1843
1844
        // -1 means infinity
1845
0
        if (uint(key.position) < uint(iniSection.position))
1846
0
            iniSection.position = key.position;
1847
0
        iniSection.keyMap[key] = j.value();
1848
0
    }
1849
1850
0
    const int sectionCount = iniMap.size();
1851
0
    QVector<QSettingsIniKey> sections;
1852
0
    sections.reserve(sectionCount);
1853
0
    for (i = iniMap.constBegin(); i != iniMap.constEnd(); ++i)
1854
0
        sections.append(QSettingsIniKey(i.key(), i.value().position));
1855
0
    std::sort(sections.begin(), sections.end());
1856
1857
0
    bool writeError = false;
1858
0
    for (int j = 0; !writeError && j < sectionCount; ++j) {
1859
0
        i = iniMap.constFind(sections.at(j));
1860
0
        Q_ASSERT(i != iniMap.constEnd());
1861
1862
0
        QByteArray realSection;
1863
1864
0
        iniEscapedKey(i.key(), realSection);
1865
1866
0
        if (realSection.isEmpty()) {
1867
0
            realSection = "[General]";
1868
0
        } else if (realSection.compare("general", Qt::CaseInsensitive) == 0) {
1869
0
            realSection = "[%General]";
1870
0
        } else {
1871
0
            realSection.prepend('[');
1872
0
            realSection.append(']');
1873
0
        }
1874
1875
0
        if (j != 0)
1876
0
            realSection.prepend(eol);
1877
0
        realSection += eol;
1878
1879
0
        device.write(realSection);
1880
1881
0
        const IniKeyMap &ents = i.value().keyMap;
1882
0
        for (IniKeyMap::const_iterator j = ents.constBegin(); j != ents.constEnd(); ++j) {
1883
0
            QByteArray block;
1884
0
            iniEscapedKey(j.key(), block);
1885
0
            block += '=';
1886
1887
0
            const QVariant &value = j.value();
1888
1889
            /*
1890
                The size() != 1 trick is necessary because
1891
                QVariant(QString("foo")).toList() returns an empty
1892
                list, not a list containing "foo".
1893
            */
1894
0
            if (value.userType() == QMetaType::QStringList
1895
0
                    || (value.userType() == QMetaType::QVariantList && value.toList().size() != 1)) {
1896
0
                iniEscapedStringList(variantListToStringList(value.toList()), block, iniCodec);
1897
0
            } else {
1898
0
                iniEscapedString(variantToString(value), block, iniCodec);
1899
0
            }
1900
0
            block += eol;
1901
0
            if (device.write(block) == -1) {
1902
0
                writeError = true;
1903
0
                break;
1904
0
            }
1905
0
        }
1906
0
    }
1907
0
    return !writeError;
1908
0
}
1909
1910
void QConfFileSettingsPrivate::ensureAllSectionsParsed(QConfFile *confFile) const
1911
0
{
1912
0
    UnparsedSettingsMap::const_iterator i = confFile->unparsedIniSections.constBegin();
1913
0
    const UnparsedSettingsMap::const_iterator end = confFile->unparsedIniSections.constEnd();
1914
1915
0
    for (; i != end; ++i) {
1916
0
        if (!QConfFileSettingsPrivate::readIniSection(i.key(), i.value(), &confFile->originalKeys, iniCodec))
1917
0
            setStatus(QSettings::FormatError);
1918
0
    }
1919
0
    confFile->unparsedIniSections.clear();
1920
0
}
1921
1922
void QConfFileSettingsPrivate::ensureSectionParsed(QConfFile *confFile,
1923
                                                   const QSettingsKey &key) const
1924
0
{
1925
0
    if (confFile->unparsedIniSections.isEmpty())
1926
0
        return;
1927
1928
0
    UnparsedSettingsMap::iterator i;
1929
1930
0
    int indexOfSlash = key.indexOf(QLatin1Char('/'));
1931
0
    if (indexOfSlash != -1) {
1932
0
        i = confFile->unparsedIniSections.upperBound(key);
1933
0
        if (i == confFile->unparsedIniSections.begin())
1934
0
            return;
1935
0
        --i;
1936
0
        if (i.key().isEmpty() || !key.startsWith(i.key()))
1937
0
            return;
1938
0
    } else {
1939
0
        i = confFile->unparsedIniSections.begin();
1940
0
        if (i == confFile->unparsedIniSections.end() || !i.key().isEmpty())
1941
0
            return;
1942
0
    }
1943
1944
0
    if (!QConfFileSettingsPrivate::readIniSection(i.key(), i.value(), &confFile->originalKeys, iniCodec))
1945
0
        setStatus(QSettings::FormatError);
1946
0
    confFile->unparsedIniSections.erase(i);
1947
0
}
1948
1949
/*!
1950
    \class QSettings
1951
    \inmodule QtCore
1952
    \brief The QSettings class provides persistent platform-independent application settings.
1953
1954
    \ingroup io
1955
1956
    \reentrant
1957
1958
    Users normally expect an application to remember its settings
1959
    (window sizes and positions, options, etc.) across sessions. This
1960
    information is often stored in the system registry on Windows,
1961
    and in property list files on \macos and iOS. On Unix systems, in the
1962
    absence of a standard, many applications (including the KDE
1963
    applications) use INI text files.
1964
1965
    QSettings is an abstraction around these technologies, enabling
1966
    you to save and restore application settings in a portable
1967
    manner. It also supports \l{registerFormat()}{custom storage
1968
    formats}.
1969
1970
    QSettings's API is based on QVariant, allowing you to save
1971
    most value-based types, such as QString, QRect, and QImage,
1972
    with the minimum of effort.
1973
1974
    If all you need is a non-persistent memory-based structure,
1975
    consider using QMap<QString, QVariant> instead.
1976
1977
    \tableofcontents section1
1978
1979
    \section1 Basic Usage
1980
1981
    When creating a QSettings object, you must pass the name of your
1982
    company or organization as well as the name of your application.
1983
    For example, if your product is called Star Runner and your
1984
    company is called MySoft, you would construct the QSettings
1985
    object as follows:
1986
1987
    \snippet settings/settings.cpp 0
1988
1989
    QSettings objects can be created either on the stack or on
1990
    the heap (i.e. using \c new). Constructing and destroying a
1991
    QSettings object is very fast.
1992
1993
    If you use QSettings from many places in your application, you
1994
    might want to specify the organization name and the application
1995
    name using QCoreApplication::setOrganizationName() and
1996
    QCoreApplication::setApplicationName(), and then use the default
1997
    QSettings constructor:
1998
1999
    \snippet settings/settings.cpp 1
2000
    \snippet settings/settings.cpp 2
2001
    \snippet settings/settings.cpp 3
2002
    \dots
2003
    \snippet settings/settings.cpp 4
2004
2005
    (Here, we also specify the organization's Internet domain. When
2006
    the Internet domain is set, it is used on \macos and iOS instead of the
2007
    organization name, since \macos and iOS applications conventionally use
2008
    Internet domains to identify themselves. If no domain is set, a
2009
    fake domain is derived from the organization name. See the
2010
    \l{Platform-Specific Notes} below for details.)
2011
2012
    QSettings stores settings. Each setting consists of a QString
2013
    that specifies the setting's name (the \e key) and a QVariant
2014
    that stores the data associated with the key. To write a setting,
2015
    use setValue(). For example:
2016
2017
    \snippet settings/settings.cpp 5
2018
2019
    If there already exists a setting with the same key, the existing
2020
    value is overwritten by the new value. For efficiency, the
2021
    changes may not be saved to permanent storage immediately. (You
2022
    can always call sync() to commit your changes.)
2023
2024
    You can get a setting's value back using value():
2025
2026
    \snippet settings/settings.cpp 6
2027
2028
    If there is no setting with the specified name, QSettings
2029
    returns a null QVariant (which can be converted to the integer 0).
2030
    You can specify another default value by passing a second
2031
    argument to value():
2032
2033
    \snippet settings/settings.cpp 7
2034
2035
    To test whether a given key exists, call contains(). To remove
2036
    the setting associated with a key, call remove(). To obtain the
2037
    list of all keys, call allKeys(). To remove all keys, call
2038
    clear().
2039
2040
    \section1 QVariant and GUI Types
2041
2042
    Because QVariant is part of the Qt Core module, it cannot provide
2043
    conversion functions to data types such as QColor, QImage, and
2044
    QPixmap, which are part of Qt GUI. In other words, there is no
2045
    \c toColor(), \c toImage(), or \c toPixmap() functions in QVariant.
2046
2047
    Instead, you can use the QVariant::value() template function.
2048
    For example:
2049
2050
    \snippet code/src_corelib_io_qsettings.cpp 0
2051
2052
    The inverse conversion (e.g., from QColor to QVariant) is
2053
    automatic for all data types supported by QVariant, including
2054
    GUI-related types:
2055
2056
    \snippet code/src_corelib_io_qsettings.cpp 1
2057
2058
    Custom types registered using qRegisterMetaType() and
2059
    qRegisterMetaTypeStreamOperators() can be stored using QSettings.
2060
2061
    \section1 Section and Key Syntax
2062
2063
    Setting keys can contain any Unicode characters. The Windows
2064
    registry and INI files use case-insensitive keys, whereas the
2065
    CFPreferences API on \macos and iOS uses case-sensitive keys. To
2066
    avoid portability problems, follow these simple rules:
2067
2068
    \list 1
2069
    \li Always refer to the same key using the same case. For example,
2070
       if you refer to a key as "text fonts" in one place in your
2071
       code, don't refer to it as "Text Fonts" somewhere else.
2072
2073
    \li Avoid key names that are identical except for the case. For
2074
       example, if you have a key called "MainWindow", don't try to
2075
       save another key as "mainwindow".
2076
2077
    \li Do not use slashes ('/' and '\\') in section or key names; the
2078
       backslash character is used to separate sub keys (see below). On
2079
       windows '\\' are converted by QSettings to '/', which makes
2080
       them identical.
2081
    \endlist
2082
2083
    You can form hierarchical keys using the '/' character as a
2084
    separator, similar to Unix file paths. For example:
2085
2086
    \snippet settings/settings.cpp 8
2087
    \snippet settings/settings.cpp 9
2088
    \snippet settings/settings.cpp 10
2089
2090
    If you want to save or restore many settings with the same
2091
    prefix, you can specify the prefix using beginGroup() and call
2092
    endGroup() at the end. Here's the same example again, but this
2093
    time using the group mechanism:
2094
2095
    \snippet settings/settings.cpp 11
2096
    \codeline
2097
    \snippet settings/settings.cpp 12
2098
2099
    If a group is set using beginGroup(), the behavior of most
2100
    functions changes consequently. Groups can be set recursively.
2101
2102
    In addition to groups, QSettings also supports an "array"
2103
    concept. See beginReadArray() and beginWriteArray() for details.
2104
2105
    \section1 Fallback Mechanism
2106
2107
    Let's assume that you have created a QSettings object with the
2108
    organization name MySoft and the application name Star Runner.
2109
    When you look up a value, up to four locations are searched in
2110
    that order:
2111
2112
    \list 1
2113
    \li a user-specific location for the Star Runner application
2114
    \li a user-specific location for all applications by MySoft
2115
    \li a system-wide location for the Star Runner application
2116
    \li a system-wide location for all applications by MySoft
2117
    \endlist
2118
2119
    (See \l{Platform-Specific Notes} below for information on what
2120
    these locations are on the different platforms supported by Qt.)
2121
2122
    If a key cannot be found in the first location, the search goes
2123
    on in the second location, and so on. This enables you to store
2124
    system-wide or organization-wide settings and to override them on
2125
    a per-user or per-application basis. To turn off this mechanism,
2126
    call setFallbacksEnabled(false).
2127
2128
    Although keys from all four locations are available for reading,
2129
    only the first file (the user-specific location for the
2130
    application at hand) is accessible for writing. To write to any
2131
    of the other files, omit the application name and/or specify
2132
    QSettings::SystemScope (as opposed to QSettings::UserScope, the
2133
    default).
2134
2135
    Let's see with an example:
2136
2137
    \snippet settings/settings.cpp 13
2138
    \snippet settings/settings.cpp 14
2139
2140
    The table below summarizes which QSettings objects access
2141
    which location. "\b{X}" means that the location is the main
2142
    location associated to the QSettings object and is used both
2143
    for reading and for writing; "o" means that the location is used
2144
    as a fallback when reading.
2145
2146
    \table
2147
    \header \li Locations               \li \c{obj1} \li \c{obj2} \li \c{obj3} \li \c{obj4}
2148
    \row    \li 1. User, Application    \li \b{X} \li          \li          \li
2149
    \row    \li 2. User, Organization   \li o        \li \b{X} \li          \li
2150
    \row    \li 3. System, Application  \li o        \li          \li \b{X} \li
2151
    \row    \li 4. System, Organization \li o        \li o        \li o        \li \b{X}
2152
    \endtable
2153
2154
    The beauty of this mechanism is that it works on all platforms
2155
    supported by Qt and that it still gives you a lot of flexibility,
2156
    without requiring you to specify any file names or registry
2157
    paths.
2158
2159
    If you want to use INI files on all platforms instead of the
2160
    native API, you can pass QSettings::IniFormat as the first
2161
    argument to the QSettings constructor, followed by the scope, the
2162
    organization name, and the application name:
2163
2164
    \snippet settings/settings.cpp 15
2165
2166
    Note that INI files lose the distinction between numeric data and the
2167
    strings used to encode them, so values written as numbers shall be read back
2168
    as QString. The numeric value can be recovered using \l QString::toInt(), \l
2169
    QString::toDouble() and related functions.
2170
2171
    The \l{tools/settingseditor}{Settings Editor} example lets you
2172
    experiment with different settings location and with fallbacks
2173
    turned on or off.
2174
2175
    \section1 Restoring the State of a GUI Application
2176
2177
    QSettings is often used to store the state of a GUI
2178
    application. The following example illustrates how to use QSettings
2179
    to save and restore the geometry of an application's main window.
2180
2181
    \snippet settings/settings.cpp 16
2182
    \codeline
2183
    \snippet settings/settings.cpp 17
2184
2185
    See \l{Window Geometry} for a discussion on why it is better to
2186
    call QWidget::resize() and QWidget::move() rather than QWidget::setGeometry()
2187
    to restore a window's geometry.
2188
2189
    The \c readSettings() and \c writeSettings() functions must be
2190
    called from the main window's constructor and close event handler
2191
    as follows:
2192
2193
    \snippet settings/settings.cpp 18
2194
    \dots
2195
    \snippet settings/settings.cpp 19
2196
    \snippet settings/settings.cpp 20
2197
    \codeline
2198
    \snippet settings/settings.cpp 21
2199
2200
    See the \l{mainwindows/application}{Application} example for a
2201
    self-contained example that uses QSettings.
2202
2203
    \section1 Accessing Settings from Multiple Threads or Processes Simultaneously
2204
2205
    QSettings is \l{reentrant}. This means that you can use
2206
    distinct QSettings object in different threads
2207
    simultaneously. This guarantee stands even when the QSettings
2208
    objects refer to the same files on disk (or to the same entries
2209
    in the system registry). If a setting is modified through one
2210
    QSettings object, the change will immediately be visible in
2211
    any other QSettings objects that operate on the same location
2212
    and that live in the same process.
2213
2214
    QSettings can safely be used from different processes (which can
2215
    be different instances of your application running at the same
2216
    time or different applications altogether) to read and write to
2217
    the same system locations, provided certain conditions are met. For
2218
    QSettings::IniFormat, it uses advisory file locking and a smart merging
2219
    algorithm to ensure data integrity. The condition for that to work is that
2220
    the writeable configuration file must be a regular file and must reside in
2221
    a directory that the current user can create new, temporary files in. If
2222
    that is not the case, then one must use setAtomicSyncRequired() to turn the
2223
    safety off.
2224
2225
    Note that sync() imports changes made by other processes (in addition to
2226
    writing the changes from this QSettings).
2227
2228
    \section1 Platform-Specific Notes
2229
2230
    \section2 Locations Where Application Settings Are Stored
2231
2232
    As mentioned in the \l{Fallback Mechanism} section, QSettings
2233
    stores settings for an application in up to four locations,
2234
    depending on whether the settings are user-specific or
2235
    system-wide and whether the settings are application-specific
2236
    or organization-wide. For simplicity, we're assuming the
2237
    organization is called MySoft and the application is called Star
2238
    Runner.
2239
2240
    On Unix systems, if the file format is NativeFormat, the
2241
    following files are used by default:
2242
2243
    \list 1
2244
    \li \c{$HOME/.config/MySoft/Star Runner.conf} (Qt for Embedded Linux: \c{$HOME/Settings/MySoft/Star Runner.conf})
2245
    \li \c{$HOME/.config/MySoft.conf} (Qt for Embedded Linux: \c{$HOME/Settings/MySoft.conf})
2246
    \li for each directory <dir> in $XDG_CONFIG_DIRS: \c{<dir>/MySoft/Star Runner.conf}
2247
    \li for each directory <dir> in $XDG_CONFIG_DIRS: \c{<dir>/MySoft.conf}
2248
    \endlist
2249
    \note If XDG_CONFIG_DIRS is unset, the default value of \c{/etc/xdg} is used.
2250
2251
    On \macos and iOS, if the file format is NativeFormat, these files are used by
2252
    default:
2253
2254
    \list 1
2255
    \li \c{$HOME/Library/Preferences/com.MySoft.Star Runner.plist}
2256
    \li \c{$HOME/Library/Preferences/com.MySoft.plist}
2257
    \li \c{/Library/Preferences/com.MySoft.Star Runner.plist}
2258
    \li \c{/Library/Preferences/com.MySoft.plist}
2259
    \endlist
2260
2261
    On Windows, NativeFormat settings are stored in the following
2262
    registry paths:
2263
2264
    \list 1
2265
    \li \c{HKEY_CURRENT_USER\Software\MySoft\Star Runner}
2266
    \li \c{HKEY_CURRENT_USER\Software\MySoft\OrganizationDefaults}
2267
    \li \c{HKEY_LOCAL_MACHINE\Software\MySoft\Star Runner}
2268
    \li \c{HKEY_LOCAL_MACHINE\Software\MySoft\OrganizationDefaults}
2269
    \endlist
2270
2271
    \note On Windows, for 32-bit programs running in WOW64 mode, settings are
2272
    stored in the following registry path:
2273
    \c{HKEY_LOCAL_MACHINE\Software\WOW6432node}.
2274
2275
    If the file format is NativeFormat, this is "Settings/MySoft/Star Runner.conf"
2276
    in the application's home directory.
2277
2278
    If the file format is IniFormat, the following files are
2279
    used on Unix, \macos, and iOS:
2280
2281
    \list 1
2282
    \li \c{$HOME/.config/MySoft/Star Runner.ini} (Qt for Embedded Linux: \c{$HOME/Settings/MySoft/Star Runner.ini})
2283
    \li \c{$HOME/.config/MySoft.ini} (Qt for Embedded Linux: \c{$HOME/Settings/MySoft.ini})
2284
    \li for each directory <dir> in $XDG_CONFIG_DIRS: \c{<dir>/MySoft/Star Runner.ini}
2285
    \li for each directory <dir> in $XDG_CONFIG_DIRS: \c{<dir>/MySoft.ini}
2286
    \endlist
2287
    \note If XDG_CONFIG_DIRS is unset, the default value of \c{/etc/xdg} is used.
2288
2289
    On Windows, the following files are used:
2290
2291
    \list 1
2292
    \li \c{FOLDERID_RoamingAppData\MySoft\Star Runner.ini}
2293
    \li \c{FOLDERID_RoamingAppData\MySoft.ini}
2294
    \li \c{FOLDERID_ProgramData\MySoft\Star Runner.ini}
2295
    \li \c{FOLDERID_ProgramData\MySoft.ini}
2296
    \endlist
2297
2298
    The identifiers prefixed by \c{FOLDERID_} are special item ID lists to be passed
2299
    to the Win32 API function \c{SHGetKnownFolderPath()} to obtain the
2300
    corresponding path.
2301
2302
    \c{FOLDERID_RoamingAppData} usually points to \tt{C:\\Users\\\e{User Name}\\AppData\\Roaming},
2303
    also shown by the environment variable \c{%APPDATA%}.
2304
2305
    \c{FOLDERID_ProgramData} usually points to \tt{C:\\ProgramData}.
2306
2307
    If the file format is IniFormat, this is "Settings/MySoft/Star Runner.ini"
2308
    in the application's home directory.
2309
2310
    The paths for the \c .ini and \c .conf files can be changed using
2311
    setPath(). On Unix, \macos, and iOS the user can override them by
2312
    setting the \c XDG_CONFIG_HOME environment variable; see
2313
    setPath() for details.
2314
2315
    \section2 Accessing INI and .plist Files Directly
2316
2317
    Sometimes you do want to access settings stored in a specific
2318
    file or registry path. On all platforms, if you want to read an
2319
    INI file directly, you can use the QSettings constructor that
2320
    takes a file name as first argument and pass QSettings::IniFormat
2321
    as second argument. For example:
2322
2323
    \snippet code/src_corelib_io_qsettings.cpp 2
2324
2325
    You can then use the QSettings object to read and write settings
2326
    in the file.
2327
2328
    On \macos and iOS, you can access property list \c .plist files by passing
2329
    QSettings::NativeFormat as second argument. For example:
2330
2331
    \snippet code/src_corelib_io_qsettings.cpp 3
2332
2333
    \section2 Accessing the Windows Registry Directly
2334
2335
    On Windows, QSettings lets you access settings that have been
2336
    written with QSettings (or settings in a supported format, e.g., string
2337
    data) in the system registry. This is done by constructing a QSettings
2338
    object with a path in the registry and QSettings::NativeFormat.
2339
2340
    For example:
2341
2342
    \snippet code/src_corelib_io_qsettings.cpp 4
2343
2344
    All the registry entries that appear under the specified path can
2345
    be read or written through the QSettings object as usual (using
2346
    forward slashes instead of backslashes). For example:
2347
2348
    \snippet code/src_corelib_io_qsettings.cpp 5
2349
2350
    Note that the backslash character is, as mentioned, used by
2351
    QSettings to separate subkeys. As a result, you cannot read or
2352
    write windows registry entries that contain slashes or
2353
    backslashes; you should use a native windows API if you need to do
2354
    so.
2355
2356
    \section2 Accessing Common Registry Settings on Windows
2357
2358
    On Windows, it is possible for a key to have both a value and subkeys.
2359
    Its default value is accessed by using "Default" or "." in
2360
    place of a subkey:
2361
2362
    \snippet code/src_corelib_io_qsettings.cpp 6
2363
2364
    On other platforms than Windows, "Default" and "." would be
2365
    treated as regular subkeys.
2366
2367
    \section2 Platform Limitations
2368
2369
    While QSettings attempts to smooth over the differences between
2370
    the different supported platforms, there are still a few
2371
    differences that you should be aware of when porting your
2372
    application:
2373
2374
    \list
2375
    \li  The Windows system registry has the following limitations: A
2376
        subkey may not exceed 255 characters, an entry's value may
2377
        not exceed 16,383 characters, and all the values of a key may
2378
        not exceed 65,535 characters. One way to work around these
2379
        limitations is to store the settings using the IniFormat
2380
        instead of the NativeFormat.
2381
2382
    \li  On Windows, when the Windows system registry is used, QSettings
2383
         does not preserve the original type of the value. Therefore,
2384
         the type of the value might change when a new value is set. For
2385
         example, a value with type \c REG_EXPAND_SZ will change to \c REG_SZ.
2386
2387
    \li  On \macos and iOS, allKeys() will return some extra keys for global
2388
        settings that apply to all applications. These keys can be
2389
        read using value() but cannot be changed, only shadowed.
2390
        Calling setFallbacksEnabled(false) will hide these global
2391
        settings.
2392
2393
    \li  On \macos and iOS, the CFPreferences API used by QSettings expects
2394
        Internet domain names rather than organization names. To
2395
        provide a uniform API, QSettings derives a fake domain name
2396
        from the organization name (unless the organization name
2397
        already is a domain name, e.g. OpenOffice.org). The algorithm
2398
        appends ".com" to the company name and replaces spaces and
2399
        other illegal characters with hyphens. If you want to specify
2400
        a different domain name, call
2401
        QCoreApplication::setOrganizationDomain(),
2402
        QCoreApplication::setOrganizationName(), and
2403
        QCoreApplication::setApplicationName() in your \c main()
2404
        function and then use the default QSettings constructor.
2405
        Another solution is to use preprocessor directives, for
2406
        example:
2407
2408
        \snippet code/src_corelib_io_qsettings.cpp 7
2409
2410
    \li On \macos, permissions to access settings not belonging to the
2411
       current user (i.e. SystemScope) have changed with 10.7 (Lion). Prior to
2412
       that version, users having admin rights could access these. For 10.7 and
2413
       10.8 (Mountain Lion), only root can. However, 10.9 (Mavericks) changes
2414
       that rule again but only for the native format (plist files).
2415
2416
    \endlist
2417
2418
    \sa QVariant, QSessionManager, {Settings Editor Example}, {Application Example}
2419
*/
2420
2421
/*! \enum QSettings::Status
2422
2423
    The following status values are possible:
2424
2425
    \value NoError  No error occurred.
2426
    \value AccessError  An access error occurred (e.g. trying to write to a read-only file).
2427
    \value FormatError  A format error occurred (e.g. loading a malformed INI file).
2428
2429
    \sa status()
2430
*/
2431
2432
/*! \enum QSettings::Format
2433
2434
    This enum type specifies the storage format used by QSettings.
2435
2436
    \value NativeFormat     Store the settings using the most
2437
                            appropriate storage format for the platform.
2438
                            On Windows, this means the system registry;
2439
                            on \macos and iOS, this means the CFPreferences
2440
                            API; on Unix, this means textual
2441
                            configuration files in INI format.
2442
    \value Registry32Format Windows only: Explicitly access the 32-bit system registry
2443
                            from a 64-bit application running on 64-bit Windows.
2444
                            On 32-bit Windows or from a 32-bit application on 64-bit Windows,
2445
                            this works the same as specifying NativeFormat.
2446
                            This enum value was added in Qt 5.7.
2447
    \value Registry64Format Windows only: Explicitly access the 64-bit system registry
2448
                            from a 32-bit application running on 64-bit Windows.
2449
                            On 32-bit Windows or from a 64-bit application on 64-bit Windows,
2450
                            this works the same as specifying NativeFormat.
2451
                            This enum value was added in Qt 5.7.
2452
    \value IniFormat        Store the settings in INI files. Note that INI files
2453
                            lose the distinction between numeric data and the
2454
                            strings used to encode them, so values written as
2455
                            numbers shall be read back as QString.
2456
2457
    \value InvalidFormat    Special value returned by registerFormat().
2458
    \omitvalue CustomFormat1
2459
    \omitvalue CustomFormat2
2460
    \omitvalue CustomFormat3
2461
    \omitvalue CustomFormat4
2462
    \omitvalue CustomFormat5
2463
    \omitvalue CustomFormat6
2464
    \omitvalue CustomFormat7
2465
    \omitvalue CustomFormat8
2466
    \omitvalue CustomFormat9
2467
    \omitvalue CustomFormat10
2468
    \omitvalue CustomFormat11
2469
    \omitvalue CustomFormat12
2470
    \omitvalue CustomFormat13
2471
    \omitvalue CustomFormat14
2472
    \omitvalue CustomFormat15
2473
    \omitvalue CustomFormat16
2474
2475
    On Unix, NativeFormat and IniFormat mean the same thing, except
2476
    that the file extension is different (\c .conf for NativeFormat,
2477
    \c .ini for IniFormat).
2478
2479
    The INI file format is a Windows file format that Qt supports on
2480
    all platforms. In the absence of an INI standard, we try to
2481
    follow what Microsoft does, with the following exceptions:
2482
2483
    \list
2484
    \li  If you store types that QVariant can't convert to QString
2485
        (e.g., QPoint, QRect, and QSize), Qt uses an \c{@}-based
2486
        syntax to encode the type. For example:
2487
2488
        \snippet code/src_corelib_io_qsettings.cpp 8
2489
2490
        To minimize compatibility issues, any \c @ that doesn't
2491
        appear at the first position in the value or that isn't
2492
        followed by a Qt type (\c Point, \c Rect, \c Size, etc.) is
2493
        treated as a normal character.
2494
2495
    \li  Although backslash is a special character in INI files, most
2496
        Windows applications don't escape backslashes (\c{\}) in file
2497
        paths:
2498
2499
        \snippet code/src_corelib_io_qsettings.cpp 9
2500
2501
        QSettings always treats backslash as a special character and
2502
        provides no API for reading or writing such entries.
2503
2504
    \li  The INI file format has severe restrictions on the syntax of
2505
        a key. Qt works around this by using \c % as an escape
2506
        character in keys. In addition, if you save a top-level
2507
        setting (a key with no slashes in it, e.g., "someKey"), it
2508
        will appear in the INI file's "General" section. To avoid
2509
        overwriting other keys, if you save something using a key
2510
        such as "General/someKey", the key will be located in the
2511
        "%General" section, \e not in the "General" section.
2512
2513
    \li  Following the philosophy that we should be liberal in what
2514
        we accept and conservative in what we generate, QSettings
2515
        will accept Latin-1 encoded INI files, but generate pure
2516
        ASCII files, where non-ASCII values are encoded using standard
2517
        INI escape sequences. To make the INI files more readable (but
2518
        potentially less compatible), call setIniCodec().
2519
    \endlist
2520
2521
    \sa registerFormat(), setPath()
2522
*/
2523
2524
/*! \enum QSettings::Scope
2525
2526
    This enum specifies whether settings are user-specific or shared
2527
    by all users of the same system.
2528
2529
    \value UserScope  Store settings in a location specific to the
2530
                      current user (e.g., in the user's home
2531
                      directory).
2532
    \value SystemScope  Store settings in a global location, so that
2533
                        all users on the same machine access the same
2534
                        set of settings.
2535
2536
    \sa setPath()
2537
*/
2538
2539
#ifndef QT_NO_QOBJECT
2540
/*!
2541
    Constructs a QSettings object for accessing settings of the
2542
    application called \a application from the organization called \a
2543
    organization, and with parent \a parent.
2544
2545
    Example:
2546
    \snippet code/src_corelib_io_qsettings.cpp 10
2547
2548
    The scope is set to QSettings::UserScope, and the format is
2549
    set to QSettings::NativeFormat (i.e. calling setDefaultFormat()
2550
    before calling this constructor has no effect).
2551
2552
    \sa setDefaultFormat(), {Fallback Mechanism}
2553
*/
2554
QSettings::QSettings(const QString &organization, const QString &application, QObject *parent)
2555
    : QObject(*QSettingsPrivate::create(NativeFormat, UserScope, organization, application),
2556
              parent)
2557
0
{
2558
0
}
2559
2560
/*!
2561
    Constructs a QSettings object for accessing settings of the
2562
    application called \a application from the organization called \a
2563
    organization, and with parent \a parent.
2564
2565
    If \a scope is QSettings::UserScope, the QSettings object searches
2566
    user-specific settings first, before it searches system-wide
2567
    settings as a fallback. If \a scope is QSettings::SystemScope, the
2568
    QSettings object ignores user-specific settings and provides
2569
    access to system-wide settings.
2570
2571
    The storage format is set to QSettings::NativeFormat (i.e. calling
2572
    setDefaultFormat() before calling this constructor has no effect).
2573
2574
    If no application name is given, the QSettings object will
2575
    only access the organization-wide \l{Fallback Mechanism}{locations}.
2576
2577
    \sa setDefaultFormat()
2578
*/
2579
QSettings::QSettings(Scope scope, const QString &organization, const QString &application,
2580
                     QObject *parent)
2581
    : QObject(*QSettingsPrivate::create(NativeFormat, scope, organization, application), parent)
2582
0
{
2583
0
}
2584
2585
/*!
2586
    Constructs a QSettings object for accessing settings of the
2587
    application called \a application from the organization called
2588
    \a organization, and with parent \a parent.
2589
2590
    If \a scope is QSettings::UserScope, the QSettings object searches
2591
    user-specific settings first, before it searches system-wide
2592
    settings as a fallback. If \a scope is
2593
    QSettings::SystemScope, the QSettings object ignores user-specific
2594
    settings and provides access to system-wide settings.
2595
2596
    If \a format is QSettings::NativeFormat, the native API is used for
2597
    storing settings. If \a format is QSettings::IniFormat, the INI format
2598
    is used.
2599
2600
    If no application name is given, the QSettings object will
2601
    only access the organization-wide \l{Fallback Mechanism}{locations}.
2602
*/
2603
QSettings::QSettings(Format format, Scope scope, const QString &organization,
2604
                     const QString &application, QObject *parent)
2605
    : QObject(*QSettingsPrivate::create(format, scope, organization, application), parent)
2606
0
{
2607
0
}
2608
2609
/*!
2610
    Constructs a QSettings object for accessing the settings
2611
    stored in the file called \a fileName, with parent \a parent. If
2612
    the file doesn't already exist, it is created.
2613
2614
    If \a format is QSettings::NativeFormat, the meaning of \a
2615
    fileName depends on the platform. On Unix, \a fileName is the
2616
    name of an INI file. On \macos and iOS, \a fileName is the name of a
2617
    \c .plist file. On Windows, \a fileName is a path in the system
2618
    registry.
2619
2620
    If \a format is QSettings::IniFormat, \a fileName is the name of an INI
2621
    file.
2622
2623
    \warning This function is provided for convenience. It works well for
2624
    accessing INI or \c .plist files generated by Qt, but might fail on some
2625
    syntaxes found in such files originated by other programs. In particular,
2626
    be aware of the following limitations:
2627
2628
    \list
2629
    \li QSettings provides no way of reading INI "path" entries, i.e., entries
2630
       with unescaped slash characters. (This is because these entries are
2631
       ambiguous and cannot be resolved automatically.)
2632
    \li In INI files, QSettings uses the \c @ character as a metacharacter in some
2633
       contexts, to encode Qt-specific data types (e.g., \c @Rect), and might
2634
       therefore misinterpret it when it occurs in pure INI files.
2635
    \endlist
2636
2637
    \sa fileName()
2638
*/
2639
QSettings::QSettings(const QString &fileName, Format format, QObject *parent)
2640
    : QObject(*QSettingsPrivate::create(fileName, format), parent)
2641
0
{
2642
0
}
2643
2644
/*!
2645
    Constructs a QSettings object for accessing settings of the
2646
    application and organization set previously with a call to
2647
    QCoreApplication::setOrganizationName(),
2648
    QCoreApplication::setOrganizationDomain(), and
2649
    QCoreApplication::setApplicationName().
2650
2651
    The scope is QSettings::UserScope and the format is
2652
    defaultFormat() (QSettings::NativeFormat by default).
2653
    Use setDefaultFormat() before calling this constructor
2654
    to change the default format used by this constructor.
2655
2656
    The code
2657
2658
    \snippet code/src_corelib_io_qsettings.cpp 11
2659
2660
    is equivalent to
2661
2662
    \snippet code/src_corelib_io_qsettings.cpp 12
2663
2664
    If QCoreApplication::setOrganizationName() and
2665
    QCoreApplication::setApplicationName() has not been previously
2666
    called, the QSettings object will not be able to read or write
2667
    any settings, and status() will return AccessError.
2668
2669
    You should supply both the domain (used by default on \macos and iOS) and
2670
    the name (used by default elsewhere), although the code will cope if you
2671
    supply only one, which will then be used (on all platforms), at odds with
2672
    the usual naming of the file on platforms for which it isn't the default.
2673
2674
    \sa QCoreApplication::setOrganizationName(),
2675
        QCoreApplication::setOrganizationDomain(),
2676
        QCoreApplication::setApplicationName(),
2677
        setDefaultFormat()
2678
*/
2679
QSettings::QSettings(QObject *parent)
2680
    : QSettings(UserScope, parent)
2681
0
{
2682
0
}
2683
2684
/*!
2685
    \since 5.13
2686
2687
    Constructs a QSettings object in the same way as
2688
    QSettings(QObject *parent) but with the given \a scope.
2689
2690
    \sa QSettings(QObject *parent)
2691
*/
2692
QSettings::QSettings(Scope scope, QObject *parent)
2693
    : QObject(*QSettingsPrivate::create(globalDefaultFormat, scope,
2694
#ifdef Q_OS_DARWIN
2695
                                        QCoreApplication::organizationDomain().isEmpty()
2696
                                            ? QCoreApplication::organizationName()
2697
                                            : QCoreApplication::organizationDomain()
2698
#else
2699
                                        QCoreApplication::organizationName().isEmpty()
2700
                                            ? QCoreApplication::organizationDomain()
2701
                                            : QCoreApplication::organizationName()
2702
#endif
2703
                                        , QCoreApplication::applicationName()),
2704
              parent)
2705
0
{
2706
0
}
2707
2708
#else
2709
QSettings::QSettings(const QString &organization, const QString &application)
2710
    : d_ptr(QSettingsPrivate::create(globalDefaultFormat, QSettings::UserScope, organization, application))
2711
{
2712
    d_ptr->q_ptr = this;
2713
}
2714
2715
QSettings::QSettings(Scope scope, const QString &organization, const QString &application)
2716
    : d_ptr(QSettingsPrivate::create(globalDefaultFormat, scope, organization, application))
2717
{
2718
    d_ptr->q_ptr = this;
2719
}
2720
2721
QSettings::QSettings(Format format, Scope scope, const QString &organization,
2722
                     const QString &application)
2723
    : d_ptr(QSettingsPrivate::create(format, scope, organization, application))
2724
{
2725
    d_ptr->q_ptr = this;
2726
}
2727
2728
QSettings::QSettings(const QString &fileName, Format format)
2729
    : d_ptr(QSettingsPrivate::create(fileName, format))
2730
{
2731
    d_ptr->q_ptr = this;
2732
}
2733
2734
# ifndef QT_BUILD_QMAKE
2735
QSettings::QSettings(Scope scope)
2736
    : d_ptr(QSettingsPrivate::create(globalDefaultFormat, scope,
2737
#  ifdef Q_OS_DARWIN
2738
                                     QCoreApplication::organizationDomain().isEmpty()
2739
                                         ? QCoreApplication::organizationName()
2740
                                         : QCoreApplication::organizationDomain()
2741
#  else
2742
                                     QCoreApplication::organizationName().isEmpty()
2743
                                         ? QCoreApplication::organizationDomain()
2744
                                         : QCoreApplication::organizationName()
2745
#  endif
2746
                                     , QCoreApplication::applicationName())
2747
              )
2748
{
2749
    d_ptr->q_ptr = this;
2750
}
2751
# endif
2752
#endif
2753
2754
/*!
2755
    Destroys the QSettings object.
2756
2757
    Any unsaved changes will eventually be written to permanent
2758
    storage.
2759
2760
    \sa sync()
2761
*/
2762
QSettings::~QSettings()
2763
0
{
2764
0
    Q_D(QSettings);
2765
0
    if (d->pendingChanges) {
2766
0
        QT_TRY {
2767
0
            d->flush();
2768
0
        } QT_CATCH(...) {
2769
0
            ; // ok. then don't flush but at least don't throw in the destructor
2770
0
        }
2771
0
    }
2772
0
}
2773
2774
/*!
2775
    Removes all entries in the primary location associated to this
2776
    QSettings object.
2777
2778
    Entries in fallback locations are not removed.
2779
2780
    If you only want to remove the entries in the current group(),
2781
    use remove("") instead.
2782
2783
    \sa remove(), setFallbacksEnabled()
2784
*/
2785
void QSettings::clear()
2786
0
{
2787
0
    Q_D(QSettings);
2788
0
    d->clear();
2789
0
    d->requestUpdate();
2790
0
}
2791
2792
/*!
2793
    Writes any unsaved changes to permanent storage, and reloads any
2794
    settings that have been changed in the meantime by another
2795
    application.
2796
2797
    This function is called automatically from QSettings's destructor and
2798
    by the event loop at regular intervals, so you normally don't need to
2799
    call it yourself.
2800
2801
    \sa status()
2802
*/
2803
void QSettings::sync()
2804
0
{
2805
0
    Q_D(QSettings);
2806
0
    d->sync();
2807
0
    d->pendingChanges = false;
2808
0
}
2809
2810
/*!
2811
    Returns the path where settings written using this QSettings
2812
    object are stored.
2813
2814
    On Windows, if the format is QSettings::NativeFormat, the return value
2815
    is a system registry path, not a file path.
2816
2817
    \sa isWritable(), format()
2818
*/
2819
QString QSettings::fileName() const
2820
0
{
2821
0
    Q_D(const QSettings);
2822
0
    return d->fileName();
2823
0
}
2824
2825
/*!
2826
    \since 4.4
2827
2828
    Returns the format used for storing the settings.
2829
2830
    \sa defaultFormat(), fileName(), scope(), organizationName(), applicationName()
2831
*/
2832
QSettings::Format QSettings::format() const
2833
0
{
2834
0
    Q_D(const QSettings);
2835
0
    return d->format;
2836
0
}
2837
2838
/*!
2839
    \since 4.4
2840
2841
    Returns the scope used for storing the settings.
2842
2843
    \sa format(), organizationName(), applicationName()
2844
*/
2845
QSettings::Scope QSettings::scope() const
2846
0
{
2847
0
    Q_D(const QSettings);
2848
0
    return d->scope;
2849
0
}
2850
2851
/*!
2852
    \since 4.4
2853
2854
    Returns the organization name used for storing the settings.
2855
2856
    \sa QCoreApplication::organizationName(), format(), scope(), applicationName()
2857
*/
2858
QString QSettings::organizationName() const
2859
0
{
2860
0
    Q_D(const QSettings);
2861
0
    return d->organizationName;
2862
0
}
2863
2864
/*!
2865
    \since 4.4
2866
2867
    Returns the application name used for storing the settings.
2868
2869
    \sa QCoreApplication::applicationName(), format(), scope(), organizationName()
2870
*/
2871
QString QSettings::applicationName() const
2872
0
{
2873
0
    Q_D(const QSettings);
2874
0
    return d->applicationName;
2875
0
}
2876
2877
#if QT_CONFIG(textcodec)
2878
2879
/*!
2880
    \since 4.5
2881
2882
    Sets the codec for accessing INI files (including \c .conf files on Unix)
2883
    to \a codec. The codec is used for decoding any data that is read from
2884
    the INI file, and for encoding any data that is written to the file. By
2885
    default, no codec is used, and non-ASCII characters are encoded using
2886
    standard INI escape sequences.
2887
2888
    \warning The codec must be set immediately after creating the QSettings
2889
    object, before accessing any data.
2890
2891
    \sa iniCodec()
2892
*/
2893
void QSettings::setIniCodec(QTextCodec *codec)
2894
0
{
2895
0
    Q_D(QSettings);
2896
0
    d->iniCodec = codec;
2897
0
}
2898
2899
/*!
2900
    \since 4.5
2901
    \overload
2902
2903
    Sets the codec for accessing INI files (including \c .conf files on Unix)
2904
    to the QTextCodec for the encoding specified by \a codecName. Common
2905
    values for \c codecName include "ISO 8859-1", "UTF-8", and "UTF-16".
2906
    If the encoding isn't recognized, nothing happens.
2907
2908
    \sa QTextCodec::codecForName()
2909
*/
2910
void QSettings::setIniCodec(const char *codecName)
2911
0
{
2912
0
    Q_D(QSettings);
2913
0
    if (QTextCodec *codec = QTextCodec::codecForName(codecName))
2914
0
        d->iniCodec = codec;
2915
0
}
2916
2917
/*!
2918
    \since 4.5
2919
2920
    Returns the codec that is used for accessing INI files. By default,
2921
    no codec is used, so \nullptr is returned.
2922
*/
2923
2924
QTextCodec *QSettings::iniCodec() const
2925
0
{
2926
0
    Q_D(const QSettings);
2927
0
    return d->iniCodec;
2928
0
}
2929
2930
#endif // textcodec
2931
2932
/*!
2933
    Returns a status code indicating the first error that was met by
2934
    QSettings, or QSettings::NoError if no error occurred.
2935
2936
    Be aware that QSettings delays performing some operations. For this
2937
    reason, you might want to call sync() to ensure that the data stored
2938
    in QSettings is written to disk before calling status().
2939
2940
    \sa sync()
2941
*/
2942
QSettings::Status QSettings::status() const
2943
0
{
2944
0
    Q_D(const QSettings);
2945
0
    return d->status;
2946
0
}
2947
2948
/*!
2949
    \since 5.10
2950
2951
    Returns \c true if QSettings is only allowed to perform atomic saving and
2952
    reloading (synchronization) of the settings. Returns \c false if it is
2953
    allowed to save the settings contents directly to the configuration file.
2954
2955
    The default is \c true.
2956
2957
    \sa setAtomicSyncRequired(), QSaveFile
2958
*/
2959
bool QSettings::isAtomicSyncRequired() const
2960
0
{
2961
0
    Q_D(const QSettings);
2962
0
    return d->atomicSyncOnly;
2963
0
}
2964
2965
/*!
2966
    \since 5.10
2967
2968
    Configures whether QSettings is required to perform atomic saving and
2969
    reloading (synchronization) of the settings. If the \a enable argument is
2970
    \c true (the default), sync() will only perform synchronization operations
2971
    that are atomic. If this is not possible, sync() will fail and status()
2972
    will be an error condition.
2973
2974
    Setting this property to \c false will allow QSettings to write directly to
2975
    the configuration file and ignore any errors trying to lock it against
2976
    other processes trying to write at the same time. Because of the potential
2977
    for corruption, this option should be used with care, but is required in
2978
    certain conditions, like a QSettings::IniFormat configuration file that
2979
    exists in an otherwise non-writeable directory or NTFS Alternate Data
2980
    Streams.
2981
2982
    See \l QSaveFile for more information on the feature.
2983
2984
    \sa isAtomicSyncRequired(), QSaveFile
2985
*/
2986
void QSettings::setAtomicSyncRequired(bool enable)
2987
0
{
2988
0
    Q_D(QSettings);
2989
0
    d->atomicSyncOnly = enable;
2990
0
}
2991
2992
/*!
2993
    Appends \a prefix to the current group.
2994
2995
    The current group is automatically prepended to all keys
2996
    specified to QSettings. In addition, query functions such as
2997
    childGroups(), childKeys(), and allKeys() are based on the group.
2998
    By default, no group is set.
2999
3000
    Groups are useful to avoid typing in the same setting paths over
3001
    and over. For example:
3002
3003
    \snippet code/src_corelib_io_qsettings.cpp 13
3004
3005
    This will set the value of three settings:
3006
3007
    \list
3008
    \li \c mainwindow/size
3009
    \li \c mainwindow/fullScreen
3010
    \li \c outputpanel/visible
3011
    \endlist
3012
3013
    Call endGroup() to reset the current group to what it was before
3014
    the corresponding beginGroup() call. Groups can be nested.
3015
3016
    \sa endGroup(), group()
3017
*/
3018
void QSettings::beginGroup(const QString &prefix)
3019
0
{
3020
0
    Q_D(QSettings);
3021
0
    d->beginGroupOrArray(QSettingsGroup(d->normalizedKey(prefix)));
3022
0
}
3023
3024
/*!
3025
    Resets the group to what it was before the corresponding
3026
    beginGroup() call.
3027
3028
    Example:
3029
3030
    \snippet code/src_corelib_io_qsettings.cpp 14
3031
3032
    \sa beginGroup(), group()
3033
*/
3034
void QSettings::endGroup()
3035
0
{
3036
0
    Q_D(QSettings);
3037
0
    if (d->groupStack.isEmpty()) {
3038
0
        qWarning("QSettings::endGroup: No matching beginGroup()");
3039
0
        return;
3040
0
    }
3041
3042
0
    QSettingsGroup group = d->groupStack.pop();
3043
0
    int len = group.toString().size();
3044
0
    if (len > 0)
3045
0
        d->groupPrefix.truncate(d->groupPrefix.size() - (len + 1));
3046
3047
0
    if (group.isArray())
3048
0
        qWarning("QSettings::endGroup: Expected endArray() instead");
3049
0
}
3050
3051
/*!
3052
    Returns the current group.
3053
3054
    \sa beginGroup(), endGroup()
3055
*/
3056
QString QSettings::group() const
3057
0
{
3058
0
    Q_D(const QSettings);
3059
0
    return d->groupPrefix.left(d->groupPrefix.size() - 1);
3060
0
}
3061
3062
/*!
3063
    Adds \a prefix to the current group and starts reading from an
3064
    array. Returns the size of the array.
3065
3066
    Example:
3067
3068
    \snippet code/src_corelib_io_qsettings.cpp 15
3069
3070
    Use beginWriteArray() to write the array in the first place.
3071
3072
    \sa beginWriteArray(), endArray(), setArrayIndex()
3073
*/
3074
int QSettings::beginReadArray(const QString &prefix)
3075
0
{
3076
0
    Q_D(QSettings);
3077
0
    d->beginGroupOrArray(QSettingsGroup(d->normalizedKey(prefix), false));
3078
0
    return value(QLatin1String("size")).toInt();
3079
0
}
3080
3081
/*!
3082
    Adds \a prefix to the current group and starts writing an array
3083
    of size \a size. If \a size is -1 (the default), it is automatically
3084
    determined based on the indexes of the entries written.
3085
3086
    If you have many occurrences of a certain set of keys, you can
3087
    use arrays to make your life easier. For example, let's suppose
3088
    that you want to save a variable-length list of user names and
3089
    passwords. You could then write:
3090
3091
    \snippet code/src_corelib_io_qsettings.cpp 16
3092
3093
    The generated keys will have the form
3094
3095
    \list
3096
    \li \c logins/size
3097
    \li \c logins/1/userName
3098
    \li \c logins/1/password
3099
    \li \c logins/2/userName
3100
    \li \c logins/2/password
3101
    \li \c logins/3/userName
3102
    \li \c logins/3/password
3103
    \li ...
3104
    \endlist
3105
3106
    To read back an array, use beginReadArray().
3107
3108
    \sa beginReadArray(), endArray(), setArrayIndex()
3109
*/
3110
void QSettings::beginWriteArray(const QString &prefix, int size)
3111
0
{
3112
0
    Q_D(QSettings);
3113
0
    d->beginGroupOrArray(QSettingsGroup(d->normalizedKey(prefix), size < 0));
3114
3115
0
    if (size < 0)
3116
0
        remove(QLatin1String("size"));
3117
0
    else
3118
0
        setValue(QLatin1String("size"), size);
3119
0
}
3120
3121
/*!
3122
    Closes the array that was started using beginReadArray() or
3123
    beginWriteArray().
3124
3125
    \sa beginReadArray(), beginWriteArray()
3126
*/
3127
void QSettings::endArray()
3128
0
{
3129
0
    Q_D(QSettings);
3130
0
    if (d->groupStack.isEmpty()) {
3131
0
        qWarning("QSettings::endArray: No matching beginArray()");
3132
0
        return;
3133
0
    }
3134
3135
0
    QSettingsGroup group = d->groupStack.top();
3136
0
    int len = group.toString().size();
3137
0
    d->groupStack.pop();
3138
0
    if (len > 0)
3139
0
        d->groupPrefix.truncate(d->groupPrefix.size() - (len + 1));
3140
3141
0
    if (group.arraySizeGuess() != -1)
3142
0
        setValue(group.name() + QLatin1String("/size"), group.arraySizeGuess());
3143
3144
0
    if (!group.isArray())
3145
0
        qWarning("QSettings::endArray: Expected endGroup() instead");
3146
0
}
3147
3148
/*!
3149
    Sets the current array index to \a i. Calls to functions such as
3150
    setValue(), value(), remove(), and contains() will operate on the
3151
    array entry at that index.
3152
3153
    You must call beginReadArray() or beginWriteArray() before you
3154
    can call this function.
3155
*/
3156
void QSettings::setArrayIndex(int i)
3157
0
{
3158
0
    Q_D(QSettings);
3159
0
    if (d->groupStack.isEmpty() || !d->groupStack.top().isArray()) {
3160
0
        qWarning("QSettings::setArrayIndex: Missing beginArray()");
3161
0
        return;
3162
0
    }
3163
3164
0
    QSettingsGroup &top = d->groupStack.top();
3165
0
    int len = top.toString().size();
3166
0
    top.setArrayIndex(qMax(i, 0));
3167
0
    d->groupPrefix.replace(d->groupPrefix.size() - len - 1, len, top.toString());
3168
0
}
3169
3170
/*!
3171
    Returns a list of all keys, including subkeys, that can be read
3172
    using the QSettings object.
3173
3174
    Example:
3175
3176
    \snippet code/src_corelib_io_qsettings.cpp 17
3177
3178
    If a group is set using beginGroup(), only the keys in the group
3179
    are returned, without the group prefix:
3180
3181
    \snippet code/src_corelib_io_qsettings.cpp 18
3182
3183
    \sa childGroups(), childKeys()
3184
*/
3185
QStringList QSettings::allKeys() const
3186
0
{
3187
0
    Q_D(const QSettings);
3188
0
    return d->children(d->groupPrefix, QSettingsPrivate::AllKeys);
3189
0
}
3190
3191
/*!
3192
    Returns a list of all top-level keys that can be read using the
3193
    QSettings object.
3194
3195
    Example:
3196
3197
    \snippet code/src_corelib_io_qsettings.cpp 19
3198
3199
    If a group is set using beginGroup(), the top-level keys in that
3200
    group are returned, without the group prefix:
3201
3202
    \snippet code/src_corelib_io_qsettings.cpp 20
3203
3204
    You can navigate through the entire setting hierarchy using
3205
    childKeys() and childGroups() recursively.
3206
3207
    \sa childGroups(), allKeys()
3208
*/
3209
QStringList QSettings::childKeys() const
3210
0
{
3211
0
    Q_D(const QSettings);
3212
0
    return d->children(d->groupPrefix, QSettingsPrivate::ChildKeys);
3213
0
}
3214
3215
/*!
3216
    Returns a list of all key top-level groups that contain keys that
3217
    can be read using the QSettings object.
3218
3219
    Example:
3220
3221
    \snippet code/src_corelib_io_qsettings.cpp 21
3222
3223
    If a group is set using beginGroup(), the first-level keys in
3224
    that group are returned, without the group prefix.
3225
3226
    \snippet code/src_corelib_io_qsettings.cpp 22
3227
3228
    You can navigate through the entire setting hierarchy using
3229
    childKeys() and childGroups() recursively.
3230
3231
    \sa childKeys(), allKeys()
3232
*/
3233
QStringList QSettings::childGroups() const
3234
0
{
3235
0
    Q_D(const QSettings);
3236
0
    return d->children(d->groupPrefix, QSettingsPrivate::ChildGroups);
3237
0
}
3238
3239
/*!
3240
    Returns \c true if settings can be written using this QSettings
3241
    object; returns \c false otherwise.
3242
3243
    One reason why isWritable() might return false is if
3244
    QSettings operates on a read-only file.
3245
3246
    \warning This function is not perfectly reliable, because the
3247
    file permissions can change at any time.
3248
3249
    \sa fileName(), status(), sync()
3250
*/
3251
bool QSettings::isWritable() const
3252
0
{
3253
0
    Q_D(const QSettings);
3254
0
    return d->isWritable();
3255
0
}
3256
3257
/*!
3258
3259
  Sets the value of setting \a key to \a value. If the \a key already
3260
  exists, the previous value is overwritten.
3261
3262
  Note that the Windows registry and INI files use case-insensitive
3263
  keys, whereas the CFPreferences API on \macos and iOS uses
3264
  case-sensitive keys. To avoid portability problems, see the
3265
  \l{Section and Key Syntax} rules.
3266
3267
  Example:
3268
3269
  \snippet code/src_corelib_io_qsettings.cpp 23
3270
3271
  \sa value(), remove(), contains()
3272
*/
3273
void QSettings::setValue(const QString &key, const QVariant &value)
3274
0
{
3275
0
    Q_D(QSettings);
3276
0
    if (key.isEmpty()) {
3277
0
        qWarning("QSettings::setValue: Empty key passed");
3278
0
        return;
3279
0
    }
3280
0
    QString k = d->actualKey(key);
3281
0
    d->set(k, value);
3282
0
    d->requestUpdate();
3283
0
}
3284
3285
/*!
3286
    Removes the setting \a key and any sub-settings of \a key.
3287
3288
    Example:
3289
3290
    \snippet code/src_corelib_io_qsettings.cpp 24
3291
3292
    Be aware that if one of the fallback locations contains a setting
3293
    with the same key, that setting will be visible after calling
3294
    remove().
3295
3296
    If \a key is an empty string, all keys in the current group() are
3297
    removed. For example:
3298
3299
    \snippet code/src_corelib_io_qsettings.cpp 25
3300
3301
    Note that the Windows registry and INI files use case-insensitive
3302
    keys, whereas the CFPreferences API on \macos and iOS uses
3303
    case-sensitive keys. To avoid portability problems, see the
3304
    \l{Section and Key Syntax} rules.
3305
3306
    \sa setValue(), value(), contains()
3307
*/
3308
void QSettings::remove(const QString &key)
3309
0
{
3310
0
    Q_D(QSettings);
3311
    /*
3312
        We cannot use actualKey(), because remove() supports empty
3313
        keys. The code is also tricky because of slash handling.
3314
    */
3315
0
    QString theKey = d->normalizedKey(key);
3316
0
    if (theKey.isEmpty())
3317
0
        theKey = group();
3318
0
    else
3319
0
        theKey.prepend(d->groupPrefix);
3320
3321
0
    if (theKey.isEmpty()) {
3322
0
        d->clear();
3323
0
    } else {
3324
0
        d->remove(theKey);
3325
0
    }
3326
0
    d->requestUpdate();
3327
0
}
3328
3329
/*!
3330
    Returns \c true if there exists a setting called \a key; returns
3331
    false otherwise.
3332
3333
    If a group is set using beginGroup(), \a key is taken to be
3334
    relative to that group.
3335
3336
    Note that the Windows registry and INI files use case-insensitive
3337
    keys, whereas the CFPreferences API on \macos and iOS uses
3338
    case-sensitive keys. To avoid portability problems, see the
3339
    \l{Section and Key Syntax} rules.
3340
3341
    \sa value(), setValue()
3342
*/
3343
bool QSettings::contains(const QString &key) const
3344
0
{
3345
0
    Q_D(const QSettings);
3346
0
    QString k = d->actualKey(key);
3347
0
    return d->get(k, nullptr);
3348
0
}
3349
3350
/*!
3351
    Sets whether fallbacks are enabled to \a b.
3352
3353
    By default, fallbacks are enabled.
3354
3355
    \sa fallbacksEnabled()
3356
*/
3357
void QSettings::setFallbacksEnabled(bool b)
3358
0
{
3359
0
    Q_D(QSettings);
3360
0
    d->fallbacks = !!b;
3361
0
}
3362
3363
/*!
3364
    Returns \c true if fallbacks are enabled; returns \c false otherwise.
3365
3366
    By default, fallbacks are enabled.
3367
3368
    \sa setFallbacksEnabled()
3369
*/
3370
bool QSettings::fallbacksEnabled() const
3371
0
{
3372
0
    Q_D(const QSettings);
3373
0
    return d->fallbacks;
3374
0
}
3375
3376
#ifndef QT_NO_QOBJECT
3377
/*!
3378
    \reimp
3379
*/
3380
bool QSettings::event(QEvent *event)
3381
0
{
3382
0
    Q_D(QSettings);
3383
0
    if (event->type() == QEvent::UpdateRequest) {
3384
0
        d->update();
3385
0
        return true;
3386
0
    }
3387
0
    return QObject::event(event);
3388
0
}
3389
#endif
3390
3391
/*!
3392
    Returns the value for setting \a key. If the setting doesn't
3393
    exist, returns \a defaultValue.
3394
3395
    If no default value is specified, a default QVariant is
3396
    returned.
3397
3398
    Note that the Windows registry and INI files use case-insensitive
3399
    keys, whereas the CFPreferences API on \macos and iOS uses
3400
    case-sensitive keys. To avoid portability problems, see the
3401
    \l{Section and Key Syntax} rules.
3402
3403
    Example:
3404
3405
    \snippet code/src_corelib_io_qsettings.cpp 26
3406
3407
    \sa setValue(), contains(), remove()
3408
*/
3409
QVariant QSettings::value(const QString &key, const QVariant &defaultValue) const
3410
0
{
3411
0
    Q_D(const QSettings);
3412
0
    if (key.isEmpty()) {
3413
0
        qWarning("QSettings::value: Empty key passed");
3414
0
        return QVariant();
3415
0
    }
3416
0
    QVariant result = defaultValue;
3417
0
    QString k = d->actualKey(key);
3418
0
    d->get(k, &result);
3419
0
    return result;
3420
0
}
3421
3422
/*!
3423
    \since 4.4
3424
3425
    Sets the default file format to the given \a format, which is used
3426
    for storing settings for the QSettings(QObject *) constructor.
3427
3428
    If no default format is set, QSettings::NativeFormat is used. See
3429
    the documentation for the QSettings constructor you are using to
3430
    see if that constructor will ignore this function.
3431
3432
    \sa format()
3433
*/
3434
void QSettings::setDefaultFormat(Format format)
3435
0
{
3436
0
    globalDefaultFormat = format;
3437
0
}
3438
3439
/*!
3440
    \since 4.4
3441
3442
    Returns default file format used for storing settings for the QSettings(QObject *) constructor.
3443
    If no default format is set, QSettings::NativeFormat is used.
3444
3445
    \sa format()
3446
*/
3447
QSettings::Format QSettings::defaultFormat()
3448
0
{
3449
0
    return globalDefaultFormat;
3450
0
}
3451
3452
#if QT_DEPRECATED_SINCE(5, 13)
3453
/*!
3454
    \obsolete
3455
3456
    Use setPath() instead.
3457
3458
    \oldcode
3459
        setSystemIniPath(path);
3460
    \newcode
3461
        setPath(QSettings::NativeFormat, QSettings::SystemScope, path);
3462
        setPath(QSettings::IniFormat, QSettings::SystemScope, path);
3463
    \endcode
3464
*/
3465
void QSettings::setSystemIniPath(const QString &dir)
3466
0
{
3467
0
    setPath(IniFormat, SystemScope, dir);
3468
0
#if !defined(Q_OS_WIN) && !defined(Q_OS_MAC)
3469
0
    setPath(NativeFormat, SystemScope, dir);
3470
0
#endif
3471
0
}
3472
3473
/*!
3474
    \obsolete
3475
3476
    Use setPath() instead.
3477
*/
3478
3479
void QSettings::setUserIniPath(const QString &dir)
3480
0
{
3481
0
    setPath(IniFormat, UserScope, dir);
3482
0
#if !defined(Q_OS_WIN) && !defined(Q_OS_MAC)
3483
0
    setPath(NativeFormat, UserScope, dir);
3484
0
#endif
3485
0
}
3486
#endif
3487
/*!
3488
    \since 4.1
3489
3490
    Sets the path used for storing settings for the given \a format
3491
    and \a scope, to \a path. The \a format can be a custom format.
3492
3493
    The table below summarizes the default values:
3494
3495
    \table
3496
    \header \li Platform         \li Format                       \li Scope       \li Path
3497
    \row    \li{1,2} Windows     \li{1,2} IniFormat               \li UserScope   \li \c FOLDERID_RoamingAppData
3498
    \row                                                        \li SystemScope \li \c FOLDERID_ProgramData
3499
    \row    \li{1,2} Unix        \li{1,2} NativeFormat, IniFormat \li UserScope   \li \c $HOME/.config
3500
    \row                                                        \li SystemScope \li \c /etc/xdg
3501
    \row    \li{1,2} Qt for Embedded Linux \li{1,2} NativeFormat, IniFormat \li UserScope   \li \c $HOME/Settings
3502
    \row                                                        \li SystemScope \li \c /etc/xdg
3503
    \row    \li{1,2} \macos and iOS   \li{1,2} IniFormat               \li UserScope   \li \c $HOME/.config
3504
    \row                                                        \li SystemScope \li \c /etc/xdg
3505
    \endtable
3506
3507
    The default UserScope paths on Unix, \macos, and iOS (\c
3508
    $HOME/.config or $HOME/Settings) can be overridden by the user by setting the
3509
    \c XDG_CONFIG_HOME environment variable. The default SystemScope
3510
    paths on Unix, \macos, and iOS (\c /etc/xdg) can be overridden when
3511
    building the Qt library using the \c configure script's \c
3512
    -sysconfdir flag (see QLibraryInfo for details).
3513
3514
    Setting the NativeFormat paths on Windows, \macos, and iOS has no
3515
    effect.
3516
3517
    \warning This function doesn't affect existing QSettings objects.
3518
3519
    \sa registerFormat()
3520
*/
3521
void QSettings::setPath(Format format, Scope scope, const QString &path)
3522
0
{
3523
0
    auto locker = qt_unique_lock(settingsGlobalMutex);
3524
0
    PathHash *pathHash = pathHashFunc();
3525
0
    if (pathHash->isEmpty())
3526
0
        locker = initDefaultPaths(std::move(locker));
3527
0
    pathHash->insert(pathHashKey(format, scope), Path(path + QDir::separator(), true));
3528
0
}
3529
3530
/*!
3531
    \typedef QSettings::SettingsMap
3532
3533
    Typedef for QMap<QString, QVariant>.
3534
3535
    \sa registerFormat()
3536
*/
3537
3538
/*!
3539
    \typedef QSettings::ReadFunc
3540
3541
    Typedef for a pointer to a function with the following signature:
3542
3543
    \snippet code/src_corelib_io_qsettings.cpp 27
3544
3545
    \c ReadFunc is used in \c registerFormat() as a pointer to a function
3546
    that reads a set of key/value pairs. \c ReadFunc should read all the
3547
    options in one pass, and return all the settings in the \c SettingsMap
3548
    container, which is initially empty.
3549
3550
    \sa WriteFunc, registerFormat()
3551
*/
3552
3553
/*!
3554
    \typedef QSettings::WriteFunc
3555
3556
    Typedef for a pointer to a function with the following signature:
3557
3558
    \snippet code/src_corelib_io_qsettings.cpp 28
3559
3560
    \c WriteFunc is used in \c registerFormat() as a pointer to a function
3561
    that writes a set of key/value pairs. \c WriteFunc is only called once,
3562
    so you need to output the settings in one go.
3563
3564
    \sa ReadFunc, registerFormat()
3565
*/
3566
3567
/*!
3568
    \since 4.1
3569
    \threadsafe
3570
3571
    Registers a custom storage format. On success, returns a special
3572
    Format value that can then be passed to the QSettings constructor.
3573
    On failure, returns InvalidFormat.
3574
3575
    The \a extension is the file
3576
    extension associated to the format (without the '.').
3577
3578
    The \a readFunc and \a writeFunc parameters are pointers to
3579
    functions that read and write a set of key/value pairs. The
3580
    QIODevice parameter to the read and write functions is always
3581
    opened in binary mode (i.e., without the QIODevice::Text flag).
3582
3583
    The \a caseSensitivity parameter specifies whether keys are case
3584
    sensitive or not. This makes a difference when looking up values
3585
    using QSettings. The default is case sensitive.
3586
3587
    By default, if you use one of the constructors that work in terms
3588
    of an organization name and an application name, the file system
3589
    locations used are the same as for IniFormat. Use setPath() to
3590
    specify other locations.
3591
3592
    Example:
3593
3594
    \snippet code/src_corelib_io_qsettings.cpp 29
3595
3596
    \sa setPath()
3597
*/
3598
QSettings::Format QSettings::registerFormat(const QString &extension, ReadFunc readFunc,
3599
                                            WriteFunc writeFunc,
3600
                                            Qt::CaseSensitivity caseSensitivity)
3601
0
{
3602
0
#ifdef QT_QSETTINGS_ALWAYS_CASE_SENSITIVE_AND_FORGET_ORIGINAL_KEY_ORDER
3603
0
    Q_ASSERT(caseSensitivity == Qt::CaseSensitive);
3604
0
#endif
3605
3606
0
    const auto locker = qt_scoped_lock(settingsGlobalMutex);
3607
0
    CustomFormatVector *customFormatVector = customFormatVectorFunc();
3608
0
    int index = customFormatVector->size();
3609
0
    if (index == 16) // the QSettings::Format enum has room for 16 custom formats
3610
0
        return QSettings::InvalidFormat;
3611
3612
0
    QConfFileCustomFormat info;
3613
0
    info.extension = QLatin1Char('.') + extension;
3614
0
    info.readFunc = readFunc;
3615
0
    info.writeFunc = writeFunc;
3616
0
    info.caseSensitivity = caseSensitivity;
3617
0
    customFormatVector->append(info);
3618
3619
0
    return QSettings::Format((int)QSettings::CustomFormat1 + index);
3620
0
}
3621
3622
QT_END_NAMESPACE
3623
3624
#ifndef QT_BOOTSTRAPPED
3625
#include "moc_qsettings.cpp"
3626
#endif