QtBase  v6.3.1
qsettings.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2020 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 "private/qtools_p.h"
52 #include "qlibraryinfo.h"
53 #include "qtemporaryfile.h"
54 #include "qstandardpaths.h"
55 #include <qdatastream.h>
56 #include <qstringconverter.h>
57 
58 #ifndef QT_NO_GEOM_VARIANT
59 #include "qsize.h"
60 #include "qpoint.h"
61 #include "qrect.h"
62 #endif // !QT_NO_GEOM_VARIANT
63 
64 #include "qcoreapplication.h"
65 
66 #ifndef QT_BOOTSTRAPPED
67 #include "qsavefile.h"
68 #include "qlockfile.h"
69 #endif
70 
71 #ifdef Q_OS_VXWORKS
72 # include <ioLib.h>
73 #endif
74 
75 #include <algorithm>
76 #include <stdlib.h>
77 
78 #ifdef Q_OS_WIN // for homedirpath reading from registry
79 # include <qt_windows.h>
80 # include <shlobj.h>
81 #endif
82 
83 #if defined(Q_OS_UNIX) && !defined(Q_OS_MAC) && !defined(Q_OS_ANDROID)
84 #define Q_XDG_PLATFORM
85 #endif
86 
87 #if !defined(QT_NO_STANDARDPATHS) && (defined(Q_XDG_PLATFORM) || defined(QT_PLATFORM_UIKIT))
88 #define QSETTINGS_USE_QSTANDARDPATHS
89 #endif
90 
91 // ************************************************************************
92 // QConfFile
93 
94 /*
95  QConfFile objects are explicitly shared within the application.
96  This ensures that modification to the settings done through one
97  QSettings object are immediately reflected in other setting
98  objects of the same application.
99 */
100 
102 
104 {
109 };
111 
114 namespace {
115  struct Path
116  {
117  // Note: Defining constructors explicitly because of buggy C++11
118  // implementation in MSVC (uniform initialization).
119  Path() {}
120  Path(const QString & p, bool ud) : path(p), userDefined(ud) {}
121  QString path;
122  bool userDefined = false;
123  };
124 }
127 
128 Q_GLOBAL_STATIC(ConfFileHash, usedHashFunc)
129 Q_GLOBAL_STATIC(ConfFileCache, unusedCacheFunc)
130 Q_GLOBAL_STATIC(PathHash, pathHashFunc)
131 Q_GLOBAL_STATIC(CustomFormatVector, customFormatVectorFunc)
132 
133 static QBasicMutex settingsGlobalMutex;
134 
135 static QSettings::Format globalDefaultFormat = QSettings::NativeFormat;
136 
137 QConfFile::QConfFile(const QString &fileName, bool _userPerms)
138  : name(fileName), size(0), ref(1), userPerms(_userPerms)
139 {
140  usedHashFunc()->insert(name, this);
141 }
142 
144 {
145  if (usedHashFunc())
146  usedHashFunc()->remove(name);
147 }
148 
150 {
153 
154  for (i = removedKeys.begin(); i != removedKeys.end(); ++i)
155  result.remove(i.key());
156  for (i = addedKeys.begin(); i != addedKeys.end(); ++i)
157  result.insert(i.key(), i.value());
158  return result;
159 }
160 
162 {
163  QFileInfo fileInfo(name);
164 
165 #ifndef QT_NO_TEMPORARYFILE
166  if (fileInfo.exists()) {
167 #endif
168  QFile file(name);
169  return file.open(QFile::ReadWrite);
170 #ifndef QT_NO_TEMPORARYFILE
171  } else {
172  // Create the directories to the file.
173  QDir dir(fileInfo.absolutePath());
174  if (!dir.exists()) {
175  if (!dir.mkpath(dir.absolutePath()))
176  return false;
177  }
178 
179  // we use a temporary file to avoid race conditions
181  return file.open();
182  }
183 #endif
184 }
185 
187 {
189 
190  ConfFileHash *usedHash = usedHashFunc();
191  ConfFileCache *unusedCache = unusedCacheFunc();
192 
193  QConfFile *confFile = nullptr;
194  const auto locker = qt_scoped_lock(settingsGlobalMutex);
195 
196  if (!(confFile = usedHash->value(absPath))) {
197  if ((confFile = unusedCache->take(absPath)))
198  usedHash->insert(absPath, confFile);
199  }
200  if (confFile) {
201  confFile->ref.ref();
202  return confFile;
203  }
204  return new QConfFile(absPath, _userPerms);
205 }
206 
208 {
209  const auto locker = qt_scoped_lock(settingsGlobalMutex);
210  unusedCacheFunc()->clear();
211 }
212 
213 // ************************************************************************
214 // QSettingsPrivate
215 
217  : format(format), scope(QSettings::UserScope /* nothing better to put */), fallbacks(true),
218  pendingChanges(false), status(QSettings::NoError)
219 {
220 }
221 
223  const QString &organization, const QString &application)
224  : format(format), scope(scope), organizationName(organization), applicationName(application),
225  fallbacks(true), pendingChanges(false), status(QSettings::NoError)
226 {
227 }
228 
230 {
231 }
232 
234 {
235  auto n = normalizedKey(key);
236  Q_ASSERT_X(!n.isEmpty(), "QSettings", "empty key");
237  return groupPrefix + n;
238 }
239 
240 /*
241  Returns a string that never starts nor ends with a slash (or an
242  empty string). Examples:
243 
244  "foo" becomes "foo"
245  "/foo//bar///" becomes "foo/bar"
246  "///" becomes ""
247 
248  This function is optimized to avoid a QString deep copy in the
249  common case where the key is already normalized.
250 */
252 {
253  QString result = key;
254 
255  int i = 0;
256  while (i < result.size()) {
257  while (result.at(i) == QLatin1Char('/')) {
258  result.remove(i, 1);
259  if (i == result.size())
260  goto after_loop;
261  }
262  while (result.at(i) != QLatin1Char('/')) {
263  ++i;
264  if (i == result.size())
265  return result;
266  }
267  ++i; // leave the slash alone
268  }
269 
270 after_loop:
271  if (!result.isEmpty())
272  result.truncate(i - 1); // remove the trailing slash
273  return result;
274 }
275 
276 // see also qsettings_win.cpp and qsettings_mac.cpp
277 
278 #if !defined(Q_OS_WIN) && !defined(Q_OS_MAC) && !defined(Q_OS_WASM)
280  const QString &organization, const QString &application)
281 {
282  return new QConfFileSettingsPrivate(format, scope, organization, application);
283 }
284 #endif
285 
286 #if !defined(Q_OS_WIN)
288 {
290 }
291 #endif
292 
294 {
295  if (spec != AllKeys) {
296  int slashPos = key.indexOf(QLatin1Char('/'));
297  if (slashPos == -1) {
298  if (spec != ChildKeys)
299  return;
300  } else {
301  if (spec != ChildGroups)
302  return;
303  key.truncate(slashPos);
304  }
305  }
306  result.append(key.toString());
307 }
308 
310 {
312  const QString name = group.name();
313  if (!name.isEmpty())
314  groupPrefix += name + QLatin1Char('/');
315 }
316 
317 /*
318  We only set an error if there isn't one set already. This way the user always gets the
319  first error that occurred. We always allow clearing errors.
320 */
321 
323 {
324  if (status == QSettings::NoError || this->status == QSettings::NoError)
325  this->status = status;
326 }
327 
329 {
330  flush();
331  pendingChanges = false;
332 }
333 
335 {
336  if (!pendingChanges) {
337  pendingChanges = true;
338 #ifndef QT_NO_QOBJECT
339  Q_Q(QSettings);
341 #else
342  update();
343 #endif
344  }
345 }
346 
348 {
350  result.reserve(l.count());
351  QVariantList::const_iterator it = l.constBegin();
352  for (; it != l.constEnd(); ++it)
353  result.append(variantToString(*it));
354  return result;
355 }
356 
358 {
359  QStringList outStringList = l;
360  for (int i = 0; i < outStringList.count(); ++i) {
361  const QString &str = outStringList.at(i);
362 
363  if (str.startsWith(QLatin1Char('@'))) {
364  if (str.length() >= 2 && str.at(1) == QLatin1Char('@')) {
365  outStringList[i].remove(0, 1);
366  } else {
367  QVariantList variantList;
368  const int stringCount = l.count();
369  variantList.reserve(stringCount);
370  for (int j = 0; j < stringCount; ++j)
371  variantList.append(stringToVariant(l.at(j)));
372  return variantList;
373  }
374  }
375  }
376  return outStringList;
377 }
378 
380 {
381  QString result;
382 
383  switch (v.metaType().id()) {
385  result = QLatin1String("@Invalid()");
386  break;
387 
388  case QMetaType::QByteArray: {
389  QByteArray a = v.toByteArray();
390  result = QLatin1String("@ByteArray(")
391  + QLatin1String(a.constData(), a.size())
392  + QLatin1Char(')');
393  break;
394  }
395 
396 #if QT_CONFIG(shortcut)
397  case QMetaType::QKeySequence:
398 #endif
399  case QMetaType::QString:
400  case QMetaType::LongLong:
401  case QMetaType::ULongLong:
402  case QMetaType::Int:
403  case QMetaType::UInt:
404  case QMetaType::Bool:
405  case QMetaType::Float:
406  case QMetaType::Double: {
407  result = v.toString();
408  if (result.contains(QChar::Null))
409  result = QLatin1String("@String(") + result + QLatin1Char(')');
410  else if (result.startsWith(QLatin1Char('@')))
411  result.prepend(QLatin1Char('@'));
412  break;
413  }
414 #ifndef QT_NO_GEOM_VARIANT
415  case QMetaType::QRect: {
416  QRect r = qvariant_cast<QRect>(v);
417  result = QString::asprintf("@Rect(%d %d %d %d)", r.x(), r.y(), r.width(), r.height());
418  break;
419  }
420  case QMetaType::QSize: {
421  QSize s = qvariant_cast<QSize>(v);
422  result = QString::asprintf("@Size(%d %d)", s.width(), s.height());
423  break;
424  }
425  case QMetaType::QPoint: {
426  QPoint p = qvariant_cast<QPoint>(v);
427  result = QString::asprintf("@Point(%d %d)", p.x(), p.y());
428  break;
429  }
430 #endif // !QT_NO_GEOM_VARIANT
431 
432  default: {
433 #ifndef QT_NO_DATASTREAM
435  const char *typeSpec;
436  if (v.userType() == QMetaType::QDateTime) {
438  typeSpec = "@DateTime(";
439  } else {
441  typeSpec = "@Variant(";
442  }
443  QByteArray a;
444  {
446  s.setVersion(version);
447  s << v;
448  }
449 
450  result = QLatin1String(typeSpec)
451  + QLatin1String(a.constData(), a.size())
452  + QLatin1Char(')');
453 #else
454  Q_ASSERT(!"QSettings: Cannot save custom types without QDataStream support");
455 #endif
456  break;
457  }
458  }
459 
460  return result;
461 }
462 
463 
465 {
466  if (s.startsWith(QLatin1Char('@'))) {
467  if (s.endsWith(QLatin1Char(')'))) {
468  if (s.startsWith(QLatin1String("@ByteArray("))) {
469  return QVariant(QStringView{s}.mid(11, s.size() - 12).toLatin1());
470  } else if (s.startsWith(QLatin1String("@String("))) {
471  return QVariant(QStringView{s}.mid(8, s.size() - 9).toString());
472  } else if (s.startsWith(QLatin1String("@Variant("))
473  || s.startsWith(QLatin1String("@DateTime("))) {
474 #ifndef QT_NO_DATASTREAM
476  int offset;
477  if (s.at(1) == QLatin1Char('D')) {
479  offset = 10;
480  } else {
482  offset = 9;
483  }
486  stream.setVersion(version);
488  stream >> result;
489  return result;
490 #else
491  Q_ASSERT(!"QSettings: Cannot load custom types without QDataStream support");
492 #endif
493 #ifndef QT_NO_GEOM_VARIANT
494  } else if (s.startsWith(QLatin1String("@Rect("))) {
496  if (args.size() == 4)
497  return QVariant(QRect(args[0].toInt(), args[1].toInt(), args[2].toInt(), args[3].toInt()));
498  } else if (s.startsWith(QLatin1String("@Size("))) {
500  if (args.size() == 2)
501  return QVariant(QSize(args[0].toInt(), args[1].toInt()));
502  } else if (s.startsWith(QLatin1String("@Point("))) {
504  if (args.size() == 2)
505  return QVariant(QPoint(args[0].toInt(), args[1].toInt()));
506 #endif
507  } else if (s == QLatin1String("@Invalid()")) {
508  return QVariant();
509  }
510 
511  }
512  if (s.startsWith(QLatin1String("@@")))
513  return QVariant(s.mid(1));
514  }
515 
516  return QVariant(s);
517 }
518 
520 {
521  result.reserve(result.length() + key.length() * 3 / 2);
522  for (int i = 0; i < key.size(); ++i) {
523  uint ch = key.at(i).unicode();
524 
525  if (ch == '/') {
526  result += '\\';
527  } else if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9')
528  || ch == '_' || ch == '-' || ch == '.') {
529  result += (char)ch;
530  } else if (ch <= 0xFF) {
531  result += '%';
534  } else {
535  result += "%U";
536  QByteArray hexCode;
537  for (int i = 0; i < 4; ++i) {
538  hexCode.prepend(QtMiscUtils::toHexUpper(ch % 16));
539  ch >>= 4;
540  }
541  result += hexCode;
542  }
543  }
544 }
545 
547 {
548  bool lowercaseOnly = true;
549  int i = from;
550  result.reserve(result.length() + (to - from));
551  while (i < to) {
552  char16_t ch = (uchar)key.at(i);
553 
554  if (ch == '\\') {
555  result += QLatin1Char('/');
556  ++i;
557  continue;
558  }
559 
560  if (ch != '%' || i == to - 1) {
561  if (uint(ch - 'A') <= 'Z' - 'A') // only for ASCII
562  lowercaseOnly = false;
563  result += ch;
564  ++i;
565  continue;
566  }
567 
568  int numDigits = 2;
569  int firstDigitPos = i + 1;
570 
571  ch = key.at(i + 1);
572  if (ch == 'U') {
573  ++firstDigitPos;
574  numDigits = 4;
575  }
576 
577  if (firstDigitPos + numDigits > to) {
578  result += QLatin1Char('%');
579  // ### missing U
580  ++i;
581  continue;
582  }
583 
584  bool ok;
585  ch = key.mid(firstDigitPos, numDigits).toUShort(&ok, 16);
586  if (!ok) {
587  result += QLatin1Char('%');
588  // ### missing U
589  ++i;
590  continue;
591  }
592 
593  QChar qch(ch);
594  if (qch.isUpper())
595  lowercaseOnly = false;
596  result += qch;
597  i = firstDigitPos + numDigits;
598  }
599  return lowercaseOnly;
600 }
601 
603 {
604  bool needsQuotes = false;
605  bool escapeNextIfDigit = false;
606  bool useCodec = !str.startsWith(QLatin1String("@ByteArray("))
607  && !str.startsWith(QLatin1String("@Variant("))
608  && !str.startsWith(QLatin1String("@DateTime("));
609 
610  int i;
611  int startPos = result.size();
612 
614 
615  result.reserve(startPos + str.size() * 3 / 2);
616  const QChar *unicode = str.unicode();
617  for (i = 0; i < str.size(); ++i) {
618  uint ch = unicode[i].unicode();
619  if (ch == ';' || ch == ',' || ch == '=')
620  needsQuotes = true;
621 
622  if (escapeNextIfDigit
623  && ((ch >= '0' && ch <= '9')
624  || (ch >= 'a' && ch <= 'f')
625  || (ch >= 'A' && ch <= 'F'))) {
626  result += "\\x" + QByteArray::number(ch, 16);
627  continue;
628  }
629 
630  escapeNextIfDigit = false;
631 
632  switch (ch) {
633  case '\0':
634  result += "\\0";
635  escapeNextIfDigit = true;
636  break;
637  case '\a':
638  result += "\\a";
639  break;
640  case '\b':
641  result += "\\b";
642  break;
643  case '\f':
644  result += "\\f";
645  break;
646  case '\n':
647  result += "\\n";
648  break;
649  case '\r':
650  result += "\\r";
651  break;
652  case '\t':
653  result += "\\t";
654  break;
655  case '\v':
656  result += "\\v";
657  break;
658  case '"':
659  case '\\':
660  result += '\\';
661  result += (char)ch;
662  break;
663  default:
664  if (ch <= 0x1F || (ch >= 0x7F && !useCodec)) {
665  result += "\\x" + QByteArray::number(ch, 16);
666  escapeNextIfDigit = true;
667  } else if (useCodec) {
668  // slow
669  result += toUtf8(unicode[i]);
670  } else {
671  result += (char)ch;
672  }
673  }
674  }
675 
676  if (needsQuotes
677  || (startPos < result.size() && (result.at(startPos) == ' '
678  || result.at(result.size() - 1) == ' '))) {
679  result.insert(startPos, '"');
680  result += '"';
681  }
682 }
683 
684 inline static void iniChopTrailingSpaces(QString &str, int limit)
685 {
686  int n = str.size() - 1;
687  QChar ch;
688  while (n >= limit && ((ch = str.at(n)) == QLatin1Char(' ') || ch == QLatin1Char('\t')))
689  str.truncate(n--);
690 }
691 
693 {
694  if (strs.isEmpty()) {
695  /*
696  We need to distinguish between empty lists and one-item
697  lists that contain an empty string. Ideally, we'd have a
698  @EmptyList() symbol but that would break compatibility
699  with Qt 4.0. @Invalid() stands for QVariant(), and
700  QVariant().toStringList() returns an empty QStringList,
701  so we're in good shape.
702  */
703  result += "@Invalid()";
704  } else {
705  for (int i = 0; i < strs.size(); ++i) {
706  if (i != 0)
707  result += ", ";
708  iniEscapedString(strs.at(i), result);
709  }
710  }
711 }
712 
714  QString &stringResult, QStringList &stringListResult)
715 {
716  static const char escapeCodes[][2] =
717  {
718  { 'a', '\a' },
719  { 'b', '\b' },
720  { 'f', '\f' },
721  { 'n', '\n' },
722  { 'r', '\r' },
723  { 't', '\t' },
724  { 'v', '\v' },
725  { '"', '"' },
726  { '?', '?' },
727  { '\'', '\'' },
728  { '\\', '\\' }
729  };
730 
731  bool isStringList = false;
732  bool inQuotedString = false;
733  bool currentValueIsQuoted = false;
734  char16_t escapeVal = 0;
735  int i = from;
736  char ch;
738 
739 StSkipSpaces:
740  while (i < to && ((ch = str.at(i)) == ' ' || ch == '\t'))
741  ++i;
742  // fallthrough
743 
744 StNormal:
745  int chopLimit = stringResult.length();
746  while (i < to) {
747  switch (str.at(i)) {
748  case '\\':
749  ++i;
750  if (i >= to)
751  goto end;
752 
753  ch = str.at(i++);
754  for (const auto &escapeCode : escapeCodes) {
755  if (ch == escapeCode[0]) {
756  stringResult += QLatin1Char(escapeCode[1]);
757  goto StNormal;
758  }
759  }
760 
761  if (ch == 'x') {
762  escapeVal = 0;
763 
764  if (i >= to)
765  goto end;
766 
767  ch = str.at(i);
768  if ((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'F') || (ch >= 'a' && ch <= 'f'))
769  goto StHexEscape;
770  } else if (ch >= '0' && ch <= '7') {
771  escapeVal = ch - '0';
772  goto StOctEscape;
773  } else if (ch == '\n' || ch == '\r') {
774  if (i < to) {
775  char ch2 = str.at(i);
776  // \n, \r, \r\n, and \n\r are legitimate line terminators in INI files
777  if ((ch2 == '\n' || ch2 == '\r') && ch2 != ch)
778  ++i;
779  }
780  } else {
781  // the character is skipped
782  }
783  chopLimit = stringResult.length();
784  break;
785  case '"':
786  ++i;
787  currentValueIsQuoted = true;
788  inQuotedString = !inQuotedString;
789  if (!inQuotedString)
790  goto StSkipSpaces;
791  break;
792  case ',':
793  if (!inQuotedString) {
794  if (!currentValueIsQuoted)
795  iniChopTrailingSpaces(stringResult, chopLimit);
796  if (!isStringList) {
797  isStringList = true;
798  stringListResult.clear();
799  stringResult.squeeze();
800  }
801  stringListResult.append(stringResult);
802  stringResult.clear();
803  currentValueIsQuoted = false;
804  ++i;
805  goto StSkipSpaces;
806  }
807  Q_FALLTHROUGH();
808  default: {
809  int j = i + 1;
810  while (j < to) {
811  ch = str.at(j);
812  if (ch == '\\' || ch == '"' || ch == ',')
813  break;
814  ++j;
815  }
816 
817  stringResult += fromUtf8(QByteArrayView(str).first(j).sliced(i));
818  i = j;
819  }
820  }
821  }
822  if (!currentValueIsQuoted)
823  iniChopTrailingSpaces(stringResult, chopLimit);
824  goto end;
825 
826 StHexEscape:
827  if (i >= to) {
828  stringResult += escapeVal;
829  goto end;
830  }
831 
832  ch = str.at(i);
833  if (ch >= 'a')
834  ch -= 'a' - 'A';
835  if ((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'F')) {
836  escapeVal <<= 4;
837  escapeVal += QtMiscUtils::fromHex(ch);
838  ++i;
839  goto StHexEscape;
840  } else {
841  stringResult += escapeVal;
842  goto StNormal;
843  }
844 
845 StOctEscape:
846  if (i >= to) {
847  stringResult += escapeVal;
848  goto end;
849  }
850 
851  ch = str.at(i);
852  if (ch >= '0' && ch <= '7') {
853  escapeVal <<= 3;
854  escapeVal += ch - '0';
855  ++i;
856  goto StOctEscape;
857  } else {
858  stringResult += escapeVal;
859  goto StNormal;
860  }
861 
862 end:
863  if (isStringList)
864  stringListResult.append(stringResult);
865  return isStringList;
866 }
867 
869 {
870  int l = s.length();
871  Q_ASSERT(l > 0);
872  Q_ASSERT(s.at(idx) == QLatin1Char('('));
873  Q_ASSERT(s.at(l - 1) == QLatin1Char(')'));
874 
876  QString item;
877 
878  for (++idx; idx < l; ++idx) {
879  QChar c = s.at(idx);
880  if (c == QLatin1Char(')')) {
881  Q_ASSERT(idx == l - 1);
882  result.append(item);
883  } else if (c == QLatin1Char(' ')) {
884  result.append(item);
885  item.clear();
886  } else {
887  item.append(c);
888  }
889  }
890 
891  return result;
892 }
893 
894 // ************************************************************************
895 // QConfFileSettingsPrivate
896 
897 void QConfFileSettingsPrivate::initFormat()
898 {
899  extension = (format == QSettings::NativeFormat) ? QLatin1String(".conf") : QLatin1String(".ini");
900  readFunc = nullptr;
901  writeFunc = nullptr;
902 #if defined(Q_OS_MAC)
903  caseSensitivity = (format == QSettings::NativeFormat) ? Qt::CaseSensitive : IniCaseSensitivity;
904 #else
905  caseSensitivity = IniCaseSensitivity;
906 #endif
907 
909  const auto locker = qt_scoped_lock(settingsGlobalMutex);
910  const CustomFormatVector *customFormatVector = customFormatVectorFunc();
911 
912  int i = (int)format - (int)QSettings::CustomFormat1;
913  if (i >= 0 && i < customFormatVector->size()) {
914  QConfFileCustomFormat info = customFormatVector->at(i);
915  extension = info.extension;
916  readFunc = info.readFunc;
917  writeFunc = info.writeFunc;
918  caseSensitivity = info.caseSensitivity;
919  }
920  }
921 }
922 
923 void QConfFileSettingsPrivate::initAccess()
924 {
925  if (!confFiles.isEmpty()) {
927  if (!readFunc)
929  }
930  }
931 
932  sync(); // loads the files the first time
933 }
934 
935 #if defined(Q_OS_WIN)
936 static QString windowsConfigPath(const KNOWNFOLDERID &type)
937 {
938  QString result;
939 
940  PWSTR path = nullptr;
941  if (SHGetKnownFolderPath(type, KF_FLAG_DONT_VERIFY, NULL, &path) == S_OK) {
943  CoTaskMemFree(path);
944  }
945 
946  if (result.isEmpty()) {
947  if (type == FOLDERID_ProgramData) {
948  result = QLatin1String("C:\\temp\\qt-common");
949  } else if (type == FOLDERID_RoamingAppData) {
950  result = QLatin1String("C:\\temp\\qt-user");
951  }
952  }
953 
954  return result;
955 }
956 #endif // Q_OS_WIN
957 
958 static inline int pathHashKey(QSettings::Format format, QSettings::Scope scope)
959 {
960  return int((uint(format) << 1) | uint(scope == QSettings::SystemScope));
961 }
962 
963 #ifndef Q_OS_WIN
964 static QString make_user_path()
965 {
966  static constexpr QChar sep = QLatin1Char('/');
967 #ifndef QSETTINGS_USE_QSTANDARDPATHS
968  // Non XDG platforms (OS X, iOS, Android...) have used this code path erroneously
969  // for some time now. Moving away from that would require migrating existing settings.
970  QByteArray env = qgetenv("XDG_CONFIG_HOME");
971  if (env.isEmpty()) {
972  return QDir::homePath() + QLatin1String("/.config/");
973  } else if (env.startsWith('/')) {
974  return QFile::decodeName(env) + sep;
975  } else {
976  return QDir::homePath() + sep + QFile::decodeName(env) + sep;
977  }
978 #else
979  // When using a proper XDG platform, use QStandardPaths rather than the above hand-written code;
980  // it makes the use of test mode from unit tests possible.
981  // Ideally all platforms should use this, but see above for the migration issue.
983 #endif
984 }
985 #endif // !Q_OS_WIN
986 
987 static std::unique_lock<QBasicMutex> initDefaultPaths(std::unique_lock<QBasicMutex> locker)
988 {
989  PathHash *pathHash = pathHashFunc();
990 
991  locker.unlock();
992 
993  /*
994  QLibraryInfo::path() uses QSettings, so in order to
995  avoid a dead-lock, we can't hold the global mutex while
996  calling it.
997  */
999 
1000  locker.lock();
1001  if (pathHash->isEmpty()) {
1002  /*
1003  Lazy initialization of pathHash. We initialize the
1004  IniFormat paths and (on Unix) the NativeFormat paths.
1005  (The NativeFormat paths are not configurable for the
1006  Windows registry and the Mac CFPreferences.)
1007  */
1008 #ifdef Q_OS_WIN
1009  const QString roamingAppDataFolder = windowsConfigPath(FOLDERID_RoamingAppData);
1010  const QString programDataFolder = windowsConfigPath(FOLDERID_ProgramData);
1011  pathHash->insert(pathHashKey(QSettings::IniFormat, QSettings::UserScope),
1012  Path(roamingAppDataFolder + QDir::separator(), false));
1013  pathHash->insert(pathHashKey(QSettings::IniFormat, QSettings::SystemScope),
1014  Path(programDataFolder + QDir::separator(), false));
1015 #else
1016  const QString userPath = make_user_path();
1017  pathHash->insert(pathHashKey(QSettings::IniFormat, QSettings::UserScope), Path(userPath, false));
1018  pathHash->insert(pathHashKey(QSettings::IniFormat, QSettings::SystemScope), Path(systemPath, false));
1019 #ifndef Q_OS_MAC
1020  pathHash->insert(pathHashKey(QSettings::NativeFormat, QSettings::UserScope), Path(userPath, false));
1021  pathHash->insert(pathHashKey(QSettings::NativeFormat, QSettings::SystemScope), Path(systemPath, false));
1022 #endif
1023 #endif // Q_OS_WIN
1024  }
1025 
1026  return locker;
1027 }
1028 
1029 static Path getPath(QSettings::Format format, QSettings::Scope scope)
1030 {
1031  Q_ASSERT((int)QSettings::NativeFormat == 0);
1032  Q_ASSERT((int)QSettings::IniFormat == 1);
1033 
1034  auto locker = qt_unique_lock(settingsGlobalMutex);
1035  PathHash *pathHash = pathHashFunc();
1036  if (pathHash->isEmpty())
1037  locker = initDefaultPaths(std::move(locker));
1038 
1039  Path result = pathHash->value(pathHashKey(format, scope));
1040  if (!result.path.isEmpty())
1041  return result;
1042 
1043  // fall back on INI path
1044  return pathHash->value(pathHashKey(QSettings::IniFormat, scope));
1045 }
1046 
1047 #if defined(QT_BUILD_INTERNAL) && defined(Q_XDG_PLATFORM) && !defined(QT_NO_STANDARDPATHS)
1048 // Note: Suitable only for autotests.
1049 void Q_AUTOTEST_EXPORT clearDefaultPaths()
1050 {
1051  const auto locker = qt_scoped_lock(settingsGlobalMutex);
1052  pathHashFunc()->clear();
1053 }
1054 #endif // QT_BUILD_INTERNAL && Q_XDG_PLATFORM && !QT_NO_STANDARDPATHS
1055 
1057  QSettings::Scope scope,
1058  const QString &organization,
1059  const QString &application)
1060  : QSettingsPrivate(format, scope, organization, application),
1061  nextPosition(0x40000000) // big positive number
1062 {
1063  initFormat();
1064 
1065  QString org = organization;
1066  if (org.isEmpty()) {
1068  org = QLatin1String("Unknown Organization");
1069  }
1070 
1071  QString appFile = org + QDir::separator() + application + extension;
1072  QString orgFile = org + extension;
1073 
1074  if (scope == QSettings::UserScope) {
1075  Path userPath = getPath(format, QSettings::UserScope);
1076  if (!application.isEmpty())
1077  confFiles.append(QConfFile::fromName(userPath.path + appFile, true));
1078  confFiles.append(QConfFile::fromName(userPath.path + orgFile, true));
1079  }
1080 
1081  Path systemPath = getPath(format, QSettings::SystemScope);
1082 #if defined(Q_XDG_PLATFORM) && !defined(QT_NO_STANDARDPATHS)
1083  // check if the systemPath wasn't overridden by QSettings::setPath()
1084  if (!systemPath.userDefined) {
1085  // Note: We can't use QStandardPaths::locateAll() as we need all the
1086  // possible files (not just the existing ones) and there is no way
1087  // to exclude user specific (XDG_CONFIG_HOME) directory from the search.
1089  // remove the QStandardLocation::writableLocation() (XDG_CONFIG_HOME)
1090  if (!dirs.isEmpty())
1091  dirs.takeFirst();
1093  if (!application.isEmpty()) {
1094  paths.reserve(dirs.size() * 2);
1095  for (const auto &dir : qAsConst(dirs))
1096  paths.append(dir + QLatin1Char('/') + appFile);
1097  } else {
1098  paths.reserve(dirs.size());
1099  }
1100  for (const auto &dir : qAsConst(dirs))
1101  paths.append(dir + QLatin1Char('/') + orgFile);
1102 
1103  // Note: No check for existence of files is done intentionally.
1104  for (const auto &path : qAsConst(paths))
1105  confFiles.append(QConfFile::fromName(path, false));
1106  } else
1107 #endif // Q_XDG_PLATFORM && !QT_NO_STANDARDPATHS
1108  {
1109  if (!application.isEmpty())
1110  confFiles.append(QConfFile::fromName(systemPath.path + appFile, false));
1111  confFiles.append(QConfFile::fromName(systemPath.path + orgFile, false));
1112  }
1113 
1114 #ifndef Q_OS_WASM // wasm needs to delay access until after file sync
1115  initAccess();
1116 #endif
1117 }
1118 
1122  nextPosition(0x40000000) // big positive number
1123 {
1124  initFormat();
1125 
1126  confFiles.append(QConfFile::fromName(fileName, true));
1127 
1128  initAccess();
1129 }
1130 
1132 {
1133  const auto locker = qt_scoped_lock(settingsGlobalMutex);
1134  ConfFileHash *usedHash = usedHashFunc();
1135  ConfFileCache *unusedCache = unusedCacheFunc();
1136 
1137  for (auto conf_file : qAsConst(confFiles)) {
1138  if (!conf_file->ref.deref()) {
1139  if (conf_file->size == 0) {
1140  delete conf_file;
1141  } else {
1142  if (usedHash)
1143  usedHash->remove(conf_file->name);
1144  if (unusedCache) {
1145  QT_TRY {
1146  // compute a better size?
1147  unusedCache->insert(conf_file->name, conf_file,
1148  10 + (conf_file->originalKeys.size() / 4));
1149  } QT_CATCH(...) {
1150  // out of memory. Do not cache the file.
1151  delete conf_file;
1152  }
1153  } else {
1154  // unusedCache is gone - delete the entry to prevent a memory leak
1155  delete conf_file;
1156  }
1157  }
1158  }
1159  }
1160 }
1161 
1163 {
1164  if (confFiles.isEmpty())
1165  return;
1166 
1167  // Note: First config file is always the most specific.
1168  QConfFile *confFile = confFiles.at(0);
1169 
1170  QSettingsKey theKey(key, caseSensitivity);
1171  QSettingsKey prefix(key + QLatin1Char('/'), caseSensitivity);
1172  const auto locker = qt_scoped_lock(confFile->mutex);
1173 
1174  ensureSectionParsed(confFile, theKey);
1175  ensureSectionParsed(confFile, prefix);
1176 
1177  ParsedSettingsMap::iterator i = confFile->addedKeys.lowerBound(prefix);
1178  while (i != confFile->addedKeys.end() && i.key().startsWith(prefix))
1179  i = confFile->addedKeys.erase(i);
1180  confFile->addedKeys.remove(theKey);
1181 
1182  ParsedSettingsMap::const_iterator j = const_cast<const ParsedSettingsMap *>(&confFile->originalKeys)->lowerBound(prefix);
1183  while (j != confFile->originalKeys.constEnd() && j.key().startsWith(prefix)) {
1184  confFile->removedKeys.insert(j.key(), QVariant());
1185  ++j;
1186  }
1187  if (confFile->originalKeys.contains(theKey))
1188  confFile->removedKeys.insert(theKey, QVariant());
1189 }
1190 
1192 {
1193  if (confFiles.isEmpty())
1194  return;
1195 
1196  // Note: First config file is always the most specific.
1197  QConfFile *confFile = confFiles.at(0);
1198 
1199  QSettingsKey theKey(key, caseSensitivity, nextPosition++);
1200  const auto locker = qt_scoped_lock(confFile->mutex);
1201  confFile->removedKeys.remove(theKey);
1202  confFile->addedKeys.insert(theKey, value);
1203 }
1204 
1205 std::optional<QVariant> QConfFileSettingsPrivate::get(const QString &key) const
1206 {
1207  QSettingsKey theKey(key, caseSensitivity);
1209  bool found = false;
1210 
1211  for (auto confFile : qAsConst(confFiles)) {
1212  const auto locker = qt_scoped_lock(confFile->mutex);
1213 
1214  if (!confFile->addedKeys.isEmpty()) {
1215  j = confFile->addedKeys.constFind(theKey);
1216  found = (j != confFile->addedKeys.constEnd());
1217  }
1218  if (!found) {
1219  ensureSectionParsed(confFile, theKey);
1220  j = confFile->originalKeys.constFind(theKey);
1221  found = (j != confFile->originalKeys.constEnd()
1222  && !confFile->removedKeys.contains(theKey));
1223  }
1224 
1225  if (found)
1226  return *j;
1227  if (!fallbacks)
1228  break;
1229  }
1230  return std::nullopt;
1231 }
1232 
1234 {
1237 
1238  QSettingsKey thePrefix(prefix, caseSensitivity);
1239  int startPos = prefix.size();
1240 
1241  for (auto confFile : qAsConst(confFiles)) {
1242  const auto locker = qt_scoped_lock(confFile->mutex);
1243 
1244  if (thePrefix.isEmpty())
1245  ensureAllSectionsParsed(confFile);
1246  else
1247  ensureSectionParsed(confFile, thePrefix);
1248 
1249  j = const_cast<const ParsedSettingsMap *>(
1250  &confFile->originalKeys)->lowerBound( thePrefix);
1251  while (j != confFile->originalKeys.constEnd() && j.key().startsWith(thePrefix)) {
1252  if (!confFile->removedKeys.contains(j.key()))
1253  processChild(QStringView{j.key().originalCaseKey()}.mid(startPos), spec, result);
1254  ++j;
1255  }
1256 
1257  j = const_cast<const ParsedSettingsMap *>(
1258  &confFile->addedKeys)->lowerBound(thePrefix);
1259  while (j != confFile->addedKeys.constEnd() && j.key().startsWith(thePrefix)) {
1260  processChild(QStringView{j.key().originalCaseKey()}.mid(startPos), spec, result);
1261  ++j;
1262  }
1263 
1264  if (!fallbacks)
1265  break;
1266  }
1267  std::sort(result.begin(), result.end());
1268  result.erase(std::unique(result.begin(), result.end()),
1269  result.end());
1270  return result;
1271 }
1272 
1274 {
1275  if (confFiles.isEmpty())
1276  return;
1277 
1278  // Note: First config file is always the most specific.
1279  QConfFile *confFile = confFiles.at(0);
1280 
1281  const auto locker = qt_scoped_lock(confFile->mutex);
1282  ensureAllSectionsParsed(confFile);
1283  confFile->addedKeys.clear();
1284  confFile->removedKeys = confFile->originalKeys;
1285 }
1286 
1288 {
1289  // people probably won't be checking the status a whole lot, so in case of
1290  // error we just try to go on and make the best of it
1291 
1292  for (auto confFile : qAsConst(confFiles)) {
1293  const auto locker = qt_scoped_lock(confFile->mutex);
1294  syncConfFile(confFile);
1295  }
1296 }
1297 
1299 {
1300  sync();
1301 }
1302 
1304 {
1305  if (confFiles.isEmpty())
1306  return QString();
1307 
1308  // Note: First config file is always the most specific.
1309  return confFiles.at(0)->name;
1310 }
1311 
1313 {
1314  if (format > QSettings::IniFormat && !writeFunc)
1315  return false;
1316 
1317  if (confFiles.isEmpty())
1318  return false;
1319 
1320  return confFiles.at(0)->isWritable();
1321 }
1322 
1323 void QConfFileSettingsPrivate::syncConfFile(QConfFile *confFile)
1324 {
1325  bool readOnly = confFile->addedKeys.isEmpty() && confFile->removedKeys.isEmpty();
1326 
1327  /*
1328  We can often optimize the read-only case, if the file on disk
1329  hasn't changed.
1330  */
1331  if (readOnly && confFile->size > 0) {
1332  QFileInfo fileInfo(confFile->name);
1333  if (confFile->size == fileInfo.size() && confFile->timeStamp == fileInfo.lastModified())
1334  return;
1335  }
1336 
1337  if (!readOnly && !confFile->isWritable()) {
1339  return;
1340  }
1341 
1342 #ifndef QT_BOOTSTRAPPED
1343  /*
1344  Use a lockfile in order to protect us against other QSettings instances
1345  trying to write the same settings at the same time.
1346 
1347  We only need to lock if we are actually writing as only concurrent writes are a problem.
1348  Concurrent read and write are not a problem because the writing operation is atomic.
1349  */
1350  QLockFile lockFile(confFile->name + QLatin1String(".lock"));
1351  if (!readOnly && !lockFile.lock() && atomicSyncOnly) {
1353  return;
1354  }
1355 #endif
1356 
1357  /*
1358  We hold the lock. Let's reread the file if it has changed
1359  since last time we read it.
1360  */
1361  QFileInfo fileInfo(confFile->name);
1362  bool mustReadFile = true;
1363  bool createFile = !fileInfo.exists();
1364 
1365  if (!readOnly)
1366  mustReadFile = (confFile->size != fileInfo.size()
1367  || (confFile->size != 0 && confFile->timeStamp != fileInfo.lastModified()));
1368 
1369  if (mustReadFile) {
1370  confFile->unparsedIniSections.clear();
1371  confFile->originalKeys.clear();
1372 
1373  QFile file(confFile->name);
1374  if (!createFile && !file.open(QFile::ReadOnly)) {
1376  return;
1377  }
1378 
1379  /*
1380  Files that we can't read (because of permissions or
1381  because they don't exist) are treated as empty files.
1382  */
1383  if (file.isReadable() && file.size() != 0) {
1384  bool ok = false;
1385 #ifdef Q_OS_MAC
1388  ok = readPlistFile(data, &confFile->originalKeys);
1389  } else
1390 #endif
1391  if (format <= QSettings::IniFormat) {
1393  ok = readIniFile(data, &confFile->unparsedIniSections);
1394  } else if (readFunc) {
1395  QSettings::SettingsMap tempNewKeys;
1396  ok = readFunc(file, tempNewKeys);
1397 
1398  if (ok) {
1400  while (i != tempNewKeys.constEnd()) {
1401  confFile->originalKeys.insert(QSettingsKey(i.key(), caseSensitivity),
1402  i.value());
1403  ++i;
1404  }
1405  }
1406  }
1407 
1408  if (!ok)
1410  }
1411 
1412  confFile->size = fileInfo.size();
1413  confFile->timeStamp = fileInfo.lastModified();
1414  }
1415 
1416  /*
1417  We also need to save the file. We still hold the file lock,
1418  so everything is under control.
1419  */
1420  if (!readOnly) {
1421  bool ok = false;
1422  ensureAllSectionsParsed(confFile);
1423  ParsedSettingsMap mergedKeys = confFile->mergedKeyMap();
1424 
1425 #if !defined(QT_BOOTSTRAPPED) && QT_CONFIG(temporaryfile)
1426  QSaveFile sf(confFile->name);
1427  sf.setDirectWriteFallback(!atomicSyncOnly);
1428 #else
1429  QFile sf(confFile->name);
1430 #endif
1431  if (!sf.open(QIODevice::WriteOnly)) {
1433  return;
1434  }
1435 
1436 #ifdef Q_OS_MAC
1438  ok = writePlistFile(sf, mergedKeys);
1439  } else
1440 #endif
1441  if (format <= QSettings::IniFormat) {
1442  ok = writeIniFile(sf, mergedKeys);
1443  } else if (writeFunc) {
1444  QSettings::SettingsMap tempOriginalKeys;
1445 
1447  while (i != mergedKeys.constEnd()) {
1448  tempOriginalKeys.insert(i.key(), i.value());
1449  ++i;
1450  }
1451  ok = writeFunc(sf, tempOriginalKeys);
1452  }
1453 
1454 #if !defined(QT_BOOTSTRAPPED) && QT_CONFIG(temporaryfile)
1455  if (ok)
1456  ok = sf.commit();
1457 #endif
1458 
1459  if (ok) {
1460  confFile->unparsedIniSections.clear();
1461  confFile->originalKeys = mergedKeys;
1462  confFile->addedKeys.clear();
1463  confFile->removedKeys.clear();
1464 
1465  QFileInfo fileInfo(confFile->name);
1466  confFile->size = fileInfo.size();
1467  confFile->timeStamp = fileInfo.lastModified();
1468 
1469  // If we have created the file, apply the file perms
1470  if (createFile) {
1471  QFile::Permissions perms = fileInfo.permissions() | QFile::ReadOwner | QFile::WriteOwner;
1472  if (!confFile->userPerms)
1474  QFile(confFile->name).setPermissions(perms);
1475  }
1476  } else {
1478  }
1479  }
1480 }
1481 
1482 enum { Space = 0x1, Special = 0x2 };
1483 
1484 static const char charTraits[256] =
1485 {
1486  // Space: '\t', '\n', '\r', ' '
1487  // Special: '\n', '\r', '"', ';', '=', '\\'
1488 
1489  0, 0, 0, 0, 0, 0, 0, 0, 0, Space, Space | Special, 0, 0, Space | Special, 0, 0,
1490  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1491  Space, 0, Special, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1492  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Special, 0, Special, 0, 0,
1493  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1494  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Special, 0, 0, 0,
1495  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1496  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1497 
1498  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1499  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1500  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1501  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1502  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1503  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1504  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1505  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
1506 };
1507 
1509  int &lineStart, int &lineLen, int &equalsPos)
1510 {
1511  int dataLen = data.length();
1512  bool inQuotes = false;
1513 
1514  equalsPos = -1;
1515 
1516  lineStart = dataPos;
1517  while (lineStart < dataLen && (charTraits[uint(uchar(data.at(lineStart)))] & Space))
1518  ++lineStart;
1519 
1520  int i = lineStart;
1521  while (i < dataLen) {
1522  char ch = data.at(i);
1523  while (!(charTraits[uchar(ch)] & Special)) {
1524  if (++i == dataLen)
1525  goto break_out_of_outer_loop;
1526  ch = data.at(i);
1527  }
1528 
1529  ++i;
1530  if (ch == '=') {
1531  if (!inQuotes && equalsPos == -1)
1532  equalsPos = i - 1;
1533  } else if (ch == '\n' || ch == '\r') {
1534  if (i == lineStart + 1) {
1535  ++lineStart;
1536  } else if (!inQuotes) {
1537  --i;
1538  goto break_out_of_outer_loop;
1539  }
1540  } else if (ch == '\\') {
1541  if (i < dataLen) {
1542  char ch = data.at(i++);
1543  if (i < dataLen) {
1544  char ch2 = data.at(i);
1545  // \n, \r, \r\n, and \n\r are legitimate line terminators in INI files
1546  if ((ch == '\n' && ch2 == '\r') || (ch == '\r' && ch2 == '\n'))
1547  ++i;
1548  }
1549  }
1550  } else if (ch == '"') {
1551  inQuotes = !inQuotes;
1552  } else {
1553  Q_ASSERT(ch == ';');
1554 
1555  if (i == lineStart + 1) {
1556  while (i < dataLen && (((ch = data.at(i)) != '\n') && ch != '\r'))
1557  ++i;
1558  while (i < dataLen && charTraits[uchar(data.at(i))] & Space)
1559  ++i;
1560  lineStart = i;
1561  } else if (!inQuotes) {
1562  --i;
1563  goto break_out_of_outer_loop;
1564  }
1565  }
1566  }
1567 
1568 break_out_of_outer_loop:
1569  dataPos = i;
1570  lineLen = i - lineStart;
1571  return lineLen > 0;
1572 }
1573 
1574 /*
1575  Returns \c false on parse error. However, as many keys are read as
1576  possible, so if the user doesn't check the status he will get the
1577  most out of the file anyway.
1578 */
1580  UnparsedSettingsMap *unparsedIniSections)
1581 {
1582 #define FLUSH_CURRENT_SECTION() \
1583  { \
1584  QByteArray &sectionData = (*unparsedIniSections)[QSettingsKey(currentSection, \
1585  IniCaseSensitivity, \
1586  sectionPosition)]; \
1587  if (!sectionData.isEmpty()) \
1588  sectionData.append('\n'); \
1589  sectionData += data.mid(currentSectionStart, lineStart - currentSectionStart); \
1590  sectionPosition = ++position; \
1591  }
1592 
1593  QString currentSection;
1594  int currentSectionStart = 0;
1595  int dataPos = 0;
1596  int lineStart;
1597  int lineLen;
1598  int equalsPos;
1599  int position = 0;
1600  int sectionPosition = 0;
1601  bool ok = true;
1602 
1603  // skip potential utf8 BOM
1604  const uchar *dd = (const uchar *)data.constData();
1605  if (data.size() >= 3 && dd[0] == 0xef && dd[1] == 0xbb && dd[2] == 0xbf)
1606  dataPos = 3;
1607 
1608  while (readIniLine(data, dataPos, lineStart, lineLen, equalsPos)) {
1609  char ch = data.at(lineStart);
1610  if (ch == '[') {
1612 
1613  // this is a section
1614  QByteArray iniSection;
1615  int idx = data.indexOf(']', lineStart);
1616  if (idx == -1 || idx >= lineStart + lineLen) {
1617  ok = false;
1618  iniSection = data.mid(lineStart + 1, lineLen - 1);
1619  } else {
1620  iniSection = data.mid(lineStart + 1, idx - lineStart - 1);
1621  }
1622 
1623  iniSection = iniSection.trimmed();
1624 
1625  if (iniSection.compare("general", Qt::CaseInsensitive) == 0) {
1626  currentSection.clear();
1627  } else {
1628  if (iniSection.compare("%general", Qt::CaseInsensitive) == 0) {
1629  currentSection = QLatin1String(iniSection.constData() + 1);
1630  } else {
1631  currentSection.clear();
1632  iniUnescapedKey(iniSection, 0, iniSection.size(), currentSection);
1633  }
1634  currentSection += QLatin1Char('/');
1635  }
1636  currentSectionStart = dataPos;
1637  }
1638  ++position;
1639  }
1640 
1641  Q_ASSERT(lineStart == data.length());
1643 
1644  return ok;
1645 
1646 #undef FLUSH_CURRENT_SECTION
1647 }
1648 
1650  ParsedSettingsMap *settingsMap)
1651 {
1652  QStringList strListValue;
1653  bool sectionIsLowercase = (section == section.originalCaseKey());
1654  int equalsPos;
1655 
1656  bool ok = true;
1657  int dataPos = 0;
1658  int lineStart;
1659  int lineLen;
1660  int position = section.originalKeyPosition();
1661 
1662  while (readIniLine(data, dataPos, lineStart, lineLen, equalsPos)) {
1663  char ch = data.at(lineStart);
1664  Q_ASSERT(ch != '[');
1665 
1666  if (equalsPos == -1) {
1667  if (ch != ';')
1668  ok = false;
1669  continue;
1670  }
1671 
1672  int keyEnd = equalsPos;
1673  while (keyEnd > lineStart && ((ch = data.at(keyEnd - 1)) == ' ' || ch == '\t'))
1674  --keyEnd;
1675  int valueStart = equalsPos + 1;
1676 
1677  QString key = section.originalCaseKey();
1678  bool keyIsLowercase = (iniUnescapedKey(data, lineStart, keyEnd, key) && sectionIsLowercase);
1679 
1680  QString strValue;
1681  strValue.reserve(lineLen - (valueStart - lineStart));
1682  bool isStringList = iniUnescapedStringList(data, valueStart, lineStart + lineLen,
1683  strValue, strListValue);
1684  QVariant variant;
1685  if (isStringList) {
1686  variant = stringListToVariantList(strListValue);
1687  } else {
1688  variant = stringToVariant(strValue);
1689  }
1690 
1691  /*
1692  We try to avoid the expensive toLower() call in
1693  QSettingsKey by passing Qt::CaseSensitive when the
1694  key is already in lowercase.
1695  */
1696  settingsMap->insert(QSettingsKey(key, keyIsLowercase ? Qt::CaseSensitive
1697  : IniCaseSensitivity,
1698  position),
1699  variant);
1700  ++position;
1701  }
1702 
1703  return ok;
1704 }
1705 
1706 class QSettingsIniKey : public QString
1707 {
1708 public:
1709  inline QSettingsIniKey() : position(-1) {}
1710  inline QSettingsIniKey(const QString &str, int pos = -1) : QString(str), position(pos) {}
1711 
1713 };
1715 
1716 static bool operator<(const QSettingsIniKey &k1, const QSettingsIniKey &k2)
1717 {
1718  if (k1.position != k2.position)
1719  return k1.position < k2.position;
1720  return static_cast<const QString &>(k1) < static_cast<const QString &>(k2);
1721 }
1722 
1724 
1726 {
1729 
1730  inline QSettingsIniSection() : position(-1) {}
1731 };
1732 
1734 
1736 
1737 /*
1738  This would be more straightforward if we didn't try to remember the original
1739  key order in the .ini file, but we do.
1740 */
1741 bool QConfFileSettingsPrivate::writeIniFile(QIODevice &device, const ParsedSettingsMap &map)
1742 {
1743  IniMap iniMap;
1745 
1746 #ifdef Q_OS_WIN
1747  const char * const eol = "\r\n";
1748 #else
1749  const char eol = '\n';
1750 #endif
1751 
1753  QString section;
1754  QSettingsIniKey key(j.key().originalCaseKey(), j.key().originalKeyPosition());
1755  int slashPos;
1756 
1757  if ((slashPos = key.indexOf(QLatin1Char('/'))) != -1) {
1758  section = key.left(slashPos);
1759  key.remove(0, slashPos + 1);
1760  }
1761 
1762  QSettingsIniSection &iniSection = iniMap[section];
1763 
1764  // -1 means infinity
1765  if (uint(key.position) < uint(iniSection.position))
1766  iniSection.position = key.position;
1767  iniSection.keyMap[key] = j.value();
1768  }
1769 
1770  const int sectionCount = iniMap.size();
1771  QList<QSettingsIniKey> sections;
1772  sections.reserve(sectionCount);
1773  for (i = iniMap.constBegin(); i != iniMap.constEnd(); ++i)
1774  sections.append(QSettingsIniKey(i.key(), i.value().position));
1775  std::sort(sections.begin(), sections.end());
1776 
1777  bool writeError = false;
1778  for (int j = 0; !writeError && j < sectionCount; ++j) {
1779  i = iniMap.constFind(sections.at(j));
1780  Q_ASSERT(i != iniMap.constEnd());
1781 
1782  QByteArray realSection;
1783 
1784  iniEscapedKey(i.key(), realSection);
1785 
1786  if (realSection.isEmpty()) {
1787  realSection = "[General]";
1788  } else if (realSection.compare("general", Qt::CaseInsensitive) == 0) {
1789  realSection = "[%General]";
1790  } else {
1791  realSection.prepend('[');
1792  realSection.append(']');
1793  }
1794 
1795  if (j != 0)
1796  realSection.prepend(eol);
1797  realSection += eol;
1798 
1799  device.write(realSection);
1800 
1801  const IniKeyMap &ents = i.value().keyMap;
1802  for (IniKeyMap::const_iterator j = ents.constBegin(); j != ents.constEnd(); ++j) {
1803  QByteArray block;
1804  iniEscapedKey(j.key(), block);
1805  block += '=';
1806 
1807  const QVariant &value = j.value();
1808 
1809  /*
1810  The size() != 1 trick is necessary because
1811  QVariant(QString("foo")).toList() returns an empty
1812  list, not a list containing "foo".
1813  */
1814  if (value.metaType().id() == QMetaType::QStringList
1815  || (value.metaType().id() == QMetaType::QVariantList && value.toList().size() != 1)) {
1817  } else {
1819  }
1820  block += eol;
1821  if (device.write(block) == -1) {
1822  writeError = true;
1823  break;
1824  }
1825  }
1826  }
1827  return !writeError;
1828 }
1829 
1830 void QConfFileSettingsPrivate::ensureAllSectionsParsed(QConfFile *confFile) const
1831 {
1834 
1835  for (; i != end; ++i) {
1836  if (!QConfFileSettingsPrivate::readIniSection(i.key(), i.value(), &confFile->originalKeys))
1838  }
1839  confFile->unparsedIniSections.clear();
1840 }
1841 
1842 void QConfFileSettingsPrivate::ensureSectionParsed(QConfFile *confFile,
1843  const QSettingsKey &key) const
1844 {
1845  if (confFile->unparsedIniSections.isEmpty())
1846  return;
1847 
1849 
1850  int indexOfSlash = key.indexOf(QLatin1Char('/'));
1851  if (indexOfSlash != -1) {
1852  i = confFile->unparsedIniSections.upperBound(key);
1853  if (i == confFile->unparsedIniSections.begin())
1854  return;
1855  --i;
1856  if (i.key().isEmpty() || !key.startsWith(i.key()))
1857  return;
1858  } else {
1859  i = confFile->unparsedIniSections.begin();
1860  if (i == confFile->unparsedIniSections.end() || !i.key().isEmpty())
1861  return;
1862  }
1863 
1864  if (!QConfFileSettingsPrivate::readIniSection(i.key(), i.value(), &confFile->originalKeys))
1866  confFile->unparsedIniSections.erase(i);
1867 }
1868 
2467 #ifndef QT_NO_QOBJECT
2482 QSettings::QSettings(const QString &organization, const QString &application, QObject *parent)
2483  : QObject(*QSettingsPrivate::create(NativeFormat, UserScope, organization, application),
2484  parent)
2485 {
2486 }
2487 
2507 QSettings::QSettings(Scope scope, const QString &organization, const QString &application,
2508  QObject *parent)
2509  : QObject(*QSettingsPrivate::create(NativeFormat, scope, organization, application), parent)
2510 {
2511 }
2512 
2531 QSettings::QSettings(Format format, Scope scope, const QString &organization,
2532  const QString &application, QObject *parent)
2533  : QObject(*QSettingsPrivate::create(format, scope, organization, application), parent)
2534 {
2535 }
2536 
2569 {
2570 }
2571 
2608  : QSettings(UserScope, parent)
2609 {
2610 }
2611 
2621  : QObject(*QSettingsPrivate::create(globalDefaultFormat, scope,
2622 #ifdef Q_OS_DARWIN
2623  QCoreApplication::organizationDomain().isEmpty()
2624  ? QCoreApplication::organizationName()
2625  : QCoreApplication::organizationDomain()
2626 #else
2627  QCoreApplication::organizationName().isEmpty()
2628  ? QCoreApplication::organizationDomain()
2629  : QCoreApplication::organizationName()
2630 #endif
2631  , QCoreApplication::applicationName()),
2632  parent)
2633 {
2634 }
2635 
2636 #else
2637 QSettings::QSettings(const QString &organization, const QString &application)
2638  : d_ptr(QSettingsPrivate::create(globalDefaultFormat, QSettings::UserScope, organization, application))
2639 {
2640  d_ptr->q_ptr = this;
2641 }
2642 
2643 QSettings::QSettings(Scope scope, const QString &organization, const QString &application)
2644  : d_ptr(QSettingsPrivate::create(globalDefaultFormat, scope, organization, application))
2645 {
2646  d_ptr->q_ptr = this;
2647 }
2648 
2649 QSettings::QSettings(Format format, Scope scope, const QString &organization,
2650  const QString &application)
2651  : d_ptr(QSettingsPrivate::create(format, scope, organization, application))
2652 {
2653  d_ptr->q_ptr = this;
2654 }
2655 
2658 {
2659  d_ptr->q_ptr = this;
2660 }
2661 
2662 QSettings::QSettings(Scope scope)
2663  : d_ptr(QSettingsPrivate::create(globalDefaultFormat, scope,
2664 # ifdef Q_OS_DARWIN
2665  QCoreApplication::organizationDomain().isEmpty()
2666  ? QCoreApplication::organizationName()
2667  : QCoreApplication::organizationDomain()
2668 # else
2669  QCoreApplication::organizationName().isEmpty()
2670  ? QCoreApplication::organizationDomain()
2671  : QCoreApplication::organizationName()
2672 # endif
2673  , QCoreApplication::applicationName())
2674  )
2675 {
2676  d_ptr->q_ptr = this;
2677 }
2678 #endif
2679 
2689 {
2690  Q_D(QSettings);
2691  if (d->pendingChanges) {
2692  // Don't cause a failing flush() to std::terminate() the whole
2693  // application - dtors are implicitly noexcept!
2694  QT_TRY {
2695  d->flush();
2696  } QT_CATCH(...) {
2697  }
2698  }
2699 }
2700 
2713 {
2714  Q_D(QSettings);
2715  d->clear();
2716  d->requestUpdate();
2717 }
2718 
2731 {
2732  Q_D(QSettings);
2733  d->sync();
2734  d->pendingChanges = false;
2735 }
2736 
2747 {
2748  Q_D(const QSettings);
2749  return d->fileName();
2750 }
2751 
2760 {
2761  Q_D(const QSettings);
2762  return d->format;
2763 }
2764 
2773 {
2774  Q_D(const QSettings);
2775  return d->scope;
2776 }
2777 
2786 {
2787  Q_D(const QSettings);
2788  return d->organizationName;
2789 }
2790 
2799 {
2800  Q_D(const QSettings);
2801  return d->applicationName;
2802 }
2803 
2815 {
2816  Q_D(const QSettings);
2817  return d->status;
2818 }
2819 
2832 {
2833  Q_D(const QSettings);
2834  return d->atomicSyncOnly;
2835 }
2836 
2859 {
2860  Q_D(QSettings);
2861  d->atomicSyncOnly = enable;
2862 }
2863 
2890 void QSettings::beginGroup(const QString &prefix)
2891 {
2892  Q_D(QSettings);
2893  d->beginGroupOrArray(QSettingsGroup(d->normalizedKey(prefix)));
2894 }
2895 
2907 {
2908  Q_D(QSettings);
2909  if (d->groupStack.isEmpty()) {
2910  qWarning("QSettings::endGroup: No matching beginGroup()");
2911  return;
2912  }
2913 
2914  QSettingsGroup group = d->groupStack.pop();
2915  int len = group.toString().size();
2916  if (len > 0)
2917  d->groupPrefix.truncate(d->groupPrefix.size() - (len + 1));
2918 
2919  if (group.isArray())
2920  qWarning("QSettings::endGroup: Expected endArray() instead");
2921 }
2922 
2929 {
2930  Q_D(const QSettings);
2931  return d->groupPrefix.left(d->groupPrefix.size() - 1);
2932 }
2933 
2947 {
2948  Q_D(QSettings);
2949  d->beginGroupOrArray(QSettingsGroup(d->normalizedKey(prefix), false));
2950  return value(QLatin1String("size")).toInt();
2951 }
2952 
2982 void QSettings::beginWriteArray(const QString &prefix, int size)
2983 {
2984  Q_D(QSettings);
2985  d->beginGroupOrArray(QSettingsGroup(d->normalizedKey(prefix), size < 0));
2986 
2987  if (size < 0)
2988  remove(QLatin1String("size"));
2989  else
2990  setValue(QLatin1String("size"), size);
2991 }
2992 
3000 {
3001  Q_D(QSettings);
3002  if (d->groupStack.isEmpty()) {
3003  qWarning("QSettings::endArray: No matching beginArray()");
3004  return;
3005  }
3006 
3007  QSettingsGroup group = d->groupStack.top();
3008  int len = group.toString().size();
3009  d->groupStack.pop();
3010  if (len > 0)
3011  d->groupPrefix.truncate(d->groupPrefix.size() - (len + 1));
3012 
3013  if (group.arraySizeGuess() != -1)
3014  setValue(group.name() + QLatin1String("/size"), group.arraySizeGuess());
3015 
3016  if (!group.isArray())
3017  qWarning("QSettings::endArray: Expected endGroup() instead");
3018 }
3019 
3029 {
3030  Q_D(QSettings);
3031  if (d->groupStack.isEmpty() || !d->groupStack.top().isArray()) {
3032  qWarning("QSettings::setArrayIndex: Missing beginArray()");
3033  return;
3034  }
3035 
3036  QSettingsGroup &top = d->groupStack.top();
3037  int len = top.toString().size();
3038  top.setArrayIndex(qMax(i, 0));
3039  d->groupPrefix.replace(d->groupPrefix.size() - len - 1, len, top.toString());
3040 }
3041 
3058 {
3059  Q_D(const QSettings);
3060  return d->children(d->groupPrefix, QSettingsPrivate::AllKeys);
3061 }
3062 
3082 {
3083  Q_D(const QSettings);
3084  return d->children(d->groupPrefix, QSettingsPrivate::ChildKeys);
3085 }
3086 
3106 {
3107  Q_D(const QSettings);
3108  return d->children(d->groupPrefix, QSettingsPrivate::ChildGroups);
3109 }
3110 
3124 {
3125  Q_D(const QSettings);
3126  return d->isWritable();
3127 }
3128 
3146 {
3147  Q_D(QSettings);
3148  if (key.isEmpty()) {
3149  qWarning("QSettings::setValue: Empty key passed");
3150  return;
3151  }
3152  d->set(d->actualKey(key), value);
3153  d->requestUpdate();
3154 }
3155 
3180 {
3181  Q_D(QSettings);
3182  /*
3183  We cannot use actualKey(), because remove() supports empty
3184  keys. The code is also tricky because of slash handling.
3185  */
3186  QString theKey = d->normalizedKey(key);
3187  if (theKey.isEmpty())
3188  theKey = group();
3189  else
3190  theKey.prepend(d->groupPrefix);
3191 
3192  if (theKey.isEmpty()) {
3193  d->clear();
3194  } else {
3195  d->remove(theKey);
3196  }
3197  d->requestUpdate();
3198 }
3199 
3214 bool QSettings::contains(const QString &key) const
3215 {
3216  Q_D(const QSettings);
3217  return d->get(d->actualKey(key)) != std::nullopt;
3218 }
3219 
3228 {
3229  Q_D(QSettings);
3230  d->fallbacks = !!b;
3231 }
3232 
3241 {
3242  Q_D(const QSettings);
3243  return d->fallbacks;
3244 }
3245 
3246 #ifndef QT_NO_QOBJECT
3251 {
3252  Q_D(QSettings);
3253  if (event->type() == QEvent::UpdateRequest) {
3254  d->update();
3255  return true;
3256  }
3257  return QObject::event(event);
3258 }
3259 #endif
3260 
3283 {
3284  Q_D(const QSettings);
3285  return d->value(key, nullptr);
3286 }
3287 
3288 QVariant QSettings::value(const QString &key, const QVariant &defaultValue) const
3289 {
3290  Q_D(const QSettings);
3291  return d->value(key, &defaultValue);
3292 }
3293 
3294 QVariant QSettingsPrivate::value(const QString &key, const QVariant *defaultValue) const
3295 {
3296  if (key.isEmpty()) {
3297  qWarning("QSettings::value: Empty key passed");
3298  return QVariant();
3299  }
3300  if (std::optional r = get(actualKey(key)))
3301  return std::move(*r);
3302  if (defaultValue)
3303  return *defaultValue;
3304  return QVariant();
3305 }
3306 
3320 {
3321  globalDefaultFormat = format;
3322 }
3323 
3333 {
3334  return globalDefaultFormat;
3335 }
3336 
3372 {
3373  auto locker = qt_unique_lock(settingsGlobalMutex);
3374  PathHash *pathHash = pathHashFunc();
3375  if (pathHash->isEmpty())
3376  locker = initDefaultPaths(std::move(locker));
3377  pathHash->insert(pathHashKey(format, scope), Path(path + QDir::separator(), true));
3378 }
3379 
3448 QSettings::Format QSettings::registerFormat(const QString &extension, ReadFunc readFunc,
3449  WriteFunc writeFunc,
3450  Qt::CaseSensitivity caseSensitivity)
3451 {
3452 #ifdef QT_QSETTINGS_ALWAYS_CASE_SENSITIVE_AND_FORGET_ORIGINAL_KEY_ORDER
3453  Q_ASSERT(caseSensitivity == Qt::CaseSensitive);
3454 #endif
3455 
3456  const auto locker = qt_scoped_lock(settingsGlobalMutex);
3457  CustomFormatVector *customFormatVector = customFormatVectorFunc();
3458  int index = customFormatVector->size();
3459  if (index == 16) // the QSettings::Format enum has room for 16 custom formats
3460  return QSettings::InvalidFormat;
3461 
3463  info.extension = QLatin1Char('.') + extension;
3464  info.readFunc = readFunc;
3465  info.writeFunc = writeFunc;
3466  info.caseSensitivity = caseSensitivity;
3467  customFormatVector->append(info);
3468 
3470 }
3471 
3473 
3474 #ifndef QT_BOOTSTRAPPED
3475 #include "moc_qsettings.cpp"
3476 #endif
small capitals from c petite p scientific i
[1]
Definition: afcover.h:80
@ Float
@ Double
FT_UInt idx
Definition: cffcmap.c:135
bool ref() noexcept
Definition: qbasicatomic.h:101
The QByteArray class provides an array of bytes.
Definition: qbytearray.h:85
QByteArray trimmed() const &
Definition: qbytearray.h:220
QByteArray & prepend(char c)
Definition: qbytearray.h:238
qsizetype size() const noexcept
Definition: qbytearray.h:470
const char * constData() const noexcept
Definition: qbytearray.h:144
bool startsWith(QByteArrayView bv) const
Definition: qbytearray.h:192
bool isEmpty() const noexcept
Definition: qbytearray.h:129
static QByteArray number(int, int base=10)
int compare(QByteArrayView a, Qt::CaseSensitivity cs=Qt::CaseSensitive) const noexcept
Definition: qbytearray.h:569
QByteArray & append(char c)
QByteArray mid(qsizetype index, qsizetype len=-1) const
Definition: qcache.h:50
bool insert(const Key &key, T *object, qsizetype cost=1)
Definition: qcache.h:218
T * take(const Key &key) noexcept(std::is_nothrow_destructible_v< Key >)
Definition: qcache.h:267
The QChar class provides a 16-bit Unicode character.
Definition: qchar.h:84
@ Null
Definition: qchar.h:87
constexpr char16_t unicode() const noexcept
Definition: qchar.h:489
constexpr bool isUpper() const noexcept
Definition: qchar.h:506
QString name
Definition: qsettings_p.h:161
QAtomicInt ref
Definition: qsettings_p.h:168
UnparsedSettingsMap unparsedIniSections
Definition: qsettings_p.h:164
ParsedSettingsMap originalKeys
Definition: qsettings_p.h:165
qint64 size
Definition: qsettings_p.h:163
bool userPerms
Definition: qsettings_p.h:170
static void clearCache()
Definition: qsettings.cpp:207
QDateTime timeStamp
Definition: qsettings_p.h:162
QMutex mutex
Definition: qsettings_p.h:169
ParsedSettingsMap removedKeys
Definition: qsettings_p.h:167
ParsedSettingsMap mergedKeyMap() const
Definition: qsettings.cpp:149
static QConfFile * fromName(const QString &name, bool _userPerms)
Definition: qsettings.cpp:186
bool isWritable() const
Definition: qsettings.cpp:161
ParsedSettingsMap addedKeys
Definition: qsettings_p.h:166
static bool readIniSection(const QSettingsKey &section, const QByteArray &data, ParsedSettingsMap *settingsMap)
Definition: qsettings.cpp:1649
void set(const QString &key, const QVariant &value) override
Definition: qsettings.cpp:1191
static bool readIniLine(const QByteArray &data, int &dataPos, int &lineStart, int &lineLen, int &equalsPos)
Definition: qsettings.cpp:1508
void flush() override
Definition: qsettings.cpp:1298
bool isWritable() const override
Definition: qsettings.cpp:1312
QString fileName() const override
Definition: qsettings.cpp:1303
QConfFileSettingsPrivate(QSettings::Format format, QSettings::Scope scope, const QString &organization, const QString &application)
Definition: qsettings.cpp:1056
void remove(const QString &key) override
Definition: qsettings.cpp:1162
bool readIniFile(const QByteArray &data, UnparsedSettingsMap *unparsedIniSections)
Definition: qsettings.cpp:1579
void sync() override
Definition: qsettings.cpp:1287
void clear() override
Definition: qsettings.cpp:1273
std::optional< QVariant > get(const QString &key) const override
Definition: qsettings.cpp:1205
The QCoreApplication class provides an event loop for Qt applications without UI.
static void postEvent(QObject *receiver, QEvent *event, int priority=Qt::NormalEventPriority)
The QDataStream class provides serialization of binary data to a QIODevice.
Definition: qdatastream.h:66
The QDir class provides access to directory structures and their contents.
Definition: qdir.h:55
static QChar separator()
Definition: qdir.h:234
static QString homePath()
Definition: qdir.cpp:2055
bool operator<(const QElapsedTimer &lhs, const QElapsedTimer &rhs) noexcept
The QEvent class is the base class of all event classes. Event objects contain event parameters.
Definition: qcoreevent.h:58
@ UpdateRequest
Definition: qcoreevent.h:126
The QFile class provides an interface for reading from and writing to files.
Definition: qfile.h:94
bool open(OpenMode flags) override
Definition: qfile.cpp:897
bool setPermissions(Permissions permissionSpec) override
Definition: qfile.cpp:1152
static QString decodeName(const QByteArray &localFileName)
Definition: qfile.h:163
qint64 size() const override
Definition: qfile.cpp:1172
The QFileInfo class provides system-independent file information.
Definition: qfileinfo.h:57
QString absoluteFilePath() const
Definition: qfileinfo.cpp:556
QString absolutePath() const
Definition: qfileinfo.cpp:599
bool exists() const
Definition: qfileinfo.cpp:697
The QHash class is a template class that provides a hash-table-based dictionary.
Definition: qhash.h:773
bool remove(const Key &key)
Definition: qhash.h:911
T value(const Key &key) const noexcept
Definition: qhash.h:997
bool isEmpty() const noexcept
Definition: qhash.h:881
iterator insert(const Key &key, const T &value)
Definition: qhash.h:1228
The QIODevice class is the base interface class of all I/O devices in Qt.
Definition: qiodevice.h:70
QByteArray readAll()
Definition: qiodevice.cpp:1268
bool isReadable() const
Definition: qiodevice.cpp:616
The QLatin1String class provides a thin wrapper around an US-ASCII/Latin-1 encoded string literal.
Definition: qstring.h:84
static QString path(LibraryPath p)
Definition: qlist.h:108
qsizetype size() const noexcept
Definition: qlist.h:414
bool isEmpty() const noexcept
Definition: qlist.h:418
iterator end()
Definition: qlist.h:624
const_reference at(qsizetype i) const noexcept
Definition: qlist.h:457
iterator begin()
Definition: qlist.h:623
void reserve(qsizetype size)
Definition: qlist.h:757
void append(parameter_type t)
Definition: qlist.h:469
QList< T > toList() const noexcept
Definition: qlist.h:727
The QLockFile class provides locking between processes using a file.
Definition: qlockfile.h:55
iterator insert(const Key &key, const T &value)
Definition: qmap.h:719
iterator erase(const_iterator it)
Definition: qmap.h:650
bool contains(const Key &key) const
Definition: qmap.h:376
size_type remove(const Key &key)
Definition: qmap.h:335
const_iterator constFind(const Key &key) const
Definition: qmap.h:686
void clear()
Definition: qmap.h:324
iterator lowerBound(const Key &key)
Definition: qmap.h:691
bool isEmpty() const
Definition: qmap.h:304
iterator begin()
Definition: qmap.h:633
iterator end()
Definition: qmap.h:637
iterator upperBound(const Key &key)
Definition: qmap.h:705
const_iterator constBegin() const
Definition: qmap.h:635
size_type size() const
Definition: qmap.h:302
const_iterator constEnd() const
Definition: qmap.h:639
@ UnknownType
Definition: qmetatype.h:346
The QMutex class provides access serialization between threads.
Definition: qmutex.h:285
QObject * q_ptr
Definition: qobject.h:98
QObjectList children
Definition: qobject.h:100
The QObject class is the base class of all Qt objects.
Definition: qobject.h:125
virtual bool event(QEvent *event)
Definition: qobject.cpp:1329
QScopedPointer< QObjectData > d_ptr
Definition: qobject.h:436
The QPoint class defines a point in the plane using integer precision.
Definition: qpoint.h:52
The QRect class defines a rectangle in the plane using integer precision.
Definition: qrect.h:59
The QSaveFile class provides an interface for safely writing to files.
Definition: qsavefile.h:60
The QSettings class provides persistent platform-independent application settings.
Definition: qsettings.h:66
static void setDefaultFormat(Format format)
Definition: qsettings.cpp:3319
void endGroup()
Definition: qsettings.cpp:2906
void endArray()
Definition: qsettings.cpp:2999
QSettings(const QString &organization, const QString &application=QString(), QObject *parent=nullptr)
Definition: qsettings.cpp:2482
static Format defaultFormat()
Definition: qsettings.cpp:3332
@ CustomFormat1
Definition: qsettings.h:94
@ NativeFormat
Definition: qsettings.h:85
@ IniFormat
Definition: qsettings.h:86
@ InvalidFormat
Definition: qsettings.h:93
@ SystemScope
Definition: qsettings.h:117
void clear()
Definition: qsettings.cpp:2712
Format format() const
Definition: qsettings.cpp:2759
QString fileName() const
Definition: qsettings.cpp:2746
void setValue(const QString &key, const QVariant &value)
Definition: qsettings.cpp:3145
void setAtomicSyncRequired(bool enable)
Definition: qsettings.cpp:2858
bool event(QEvent *event) override
Definition: qsettings.cpp:3250
QVariant value(const QString &key, const QVariant &defaultValue) const
Definition: qsettings.cpp:3288
void remove(const QString &key)
Definition: qsettings.cpp:3179
QString organizationName() const
Definition: qsettings.cpp:2785
QStringList childKeys() const
Definition: qsettings.cpp:3081
bool(* WriteFunc)(QIODevice &device, const SettingsMap &map)
Definition: qsettings.h:187
static Format registerFormat(const QString &extension, ReadFunc readFunc, WriteFunc writeFunc, Qt::CaseSensitivity caseSensitivity=Qt::CaseSensitive)
Definition: qsettings.cpp:3448
QString applicationName() const
Definition: qsettings.cpp:2798
void beginGroup(const QString &prefix)
Definition: qsettings.cpp:2890
bool contains(const QString &key) const
Definition: qsettings.cpp:3214
QStringList allKeys() const
Definition: qsettings.cpp:3057
void sync()
Definition: qsettings.cpp:2730
@ FormatError
Definition: qsettings.h:78
@ AccessError
Definition: qsettings.h:77
Scope scope() const
Definition: qsettings.cpp:2772
bool isWritable() const
Definition: qsettings.cpp:3123
int beginReadArray(const QString &prefix)
Definition: qsettings.cpp:2946
bool(* ReadFunc)(QIODevice &device, SettingsMap &map)
Definition: qsettings.h:186
static void setPath(Format format, Scope scope, const QString &path)
Definition: qsettings.cpp:3371
bool isAtomicSyncRequired() const
Definition: qsettings.cpp:2831
QStringList childGroups() const
Definition: qsettings.cpp:3105
void beginWriteArray(const QString &prefix, int size=-1)
Definition: qsettings.cpp:2982
void setArrayIndex(int i)
Definition: qsettings.cpp:3028
QString group() const
Definition: qsettings.cpp:2928
Status status() const
Definition: qsettings.cpp:2814
bool fallbacksEnabled() const
Definition: qsettings.cpp:3240
void setFallbacksEnabled(bool b)
Definition: qsettings.cpp:3227
QSettingsIniKey(const QString &str, int pos=-1)
Definition: qsettings.cpp:1710
QString originalCaseKey() const
Definition: qsettings_p.h:86
int originalKeyPosition() const
Definition: qsettings_p.h:87
static void iniEscapedKey(const QString &key, QByteArray &result)
Definition: qsettings.cpp:519
virtual QString fileName() const =0
QSettingsPrivate(QSettings::Format format)
Definition: qsettings.cpp:216
QSettings::Status status
Definition: qsettings_p.h:251
static QStringList variantListToStringList(const QVariantList &l)
Definition: qsettings.cpp:347
static QSettingsPrivate * create(QSettings::Format format, QSettings::Scope scope, const QString &organization, const QString &application)
Definition: qsettings.cpp:279
static QStringList splitArgs(const QString &s, int idx)
Definition: qsettings.cpp:868
static void iniEscapedString(const QString &str, QByteArray &result)
Definition: qsettings.cpp:602
void beginGroupOrArray(const QSettingsGroup &group)
Definition: qsettings.cpp:309
void requestUpdate()
Definition: qsettings.cpp:334
static bool iniUnescapedKey(const QByteArray &key, int from, int to, QString &result)
Definition: qsettings.cpp:546
void setStatus(QSettings::Status status) const
Definition: qsettings.cpp:322
static QVariant stringListToVariantList(const QStringList &l)
Definition: qsettings.cpp:357
static QString normalizedKey(const QString &key)
Definition: qsettings.cpp:251
static QVariant stringToVariant(const QString &s)
Definition: qsettings.cpp:464
QString actualKey(const QString &key) const
Definition: qsettings.cpp:233
virtual ~QSettingsPrivate()
Definition: qsettings.cpp:229
static void iniEscapedStringList(const QStringList &strs, QByteArray &result)
Definition: qsettings.cpp:692
static bool iniUnescapedStringList(const QByteArray &str, int from, int to, QString &stringResult, QStringList &stringListResult)
Definition: qsettings.cpp:713
static QString variantToString(const QVariant &v)
Definition: qsettings.cpp:379
virtual std::optional< QVariant > get(const QString &key) const =0
virtual void flush()=0
QString groupPrefix
Definition: qsettings_p.h:247
QStack< QSettingsGroup > groupStack
Definition: qsettings_p.h:246
QVariant value(const QString &key, const QVariant *defaultValue) const
Definition: qsettings.cpp:3294
QSettings::Scope scope
Definition: qsettings_p.h:241
static void processChild(QStringView key, ChildSpec spec, QStringList &result)
Definition: qsettings.cpp:293
The QSize class defines the size of a two-dimensional object using integer point precision.
Definition: qsize.h:55
void push(const T &t)
Definition: qstack.h:53
static QStringList standardLocations(StandardLocation type)
static QString writableLocation(StandardLocation type)
The QStringDecoder class provides a state-based decoder for text. \reentrant.
The QStringEncoder class provides a state-based encoder for text. \reentrant.
The QString class provides a Unicode character string.
Definition: qstring.h:388
QString & prepend(QChar c)
Definition: qstring.h:656
bool startsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Definition: qstring.cpp:5092
void reserve(qsizetype size)
Definition: qstring.h:1307
void truncate(qsizetype pos)
Definition: qstring.cpp:5934
void clear()
Definition: qstring.h:1240
qsizetype size() const
Definition: qstring.h:413
const QChar at(qsizetype i) const
Definition: qstring.h:1212
bool isEmpty() const
Definition: qstring.h:1216
static QString fromWCharArray(const wchar_t *string, qsizetype size=-1)
QString left(qsizetype n) const
Definition: qstring.cpp:4951
void squeeze()
Definition: qstring.h:1315
QString & remove(qsizetype i, qsizetype len)
Definition: qstring.cpp:3252
static QString static QString asprintf(const char *format,...) Q_ATTRIBUTE_FORMAT_PRINTF(1
Definition: qstring.cpp:6759
qsizetype length() const
Definition: qstring.h:415
const QChar * unicode() const
Definition: qstring.h:1218
The QStringList class provides a list of strings.
The QStringView class provides a unified view on UTF-16 strings with a read-only subset of the QStrin...
Definition: qstringview.h:122
QByteArray toLatin1() const
Definition: qstringview.h:254
QString toString() const
Definition: qstring.h:1165
constexpr QStringView mid(qsizetype pos, qsizetype n=-1) const noexcept
Definition: qstringview.h:261
The QTemporaryFile class is an I/O device that operates on temporary files.
The QVariant class acts like a union for the most common Qt data types.
Definition: qvariant.h:95
int toInt(bool *ok=nullptr) const
Definition: qvariant.cpp:1833
QMap< QString, QString > map
[6]
QString str
[2]
int const char * version
Definition: zlib.h:814
else
Definition: ftgrays.c:1658
#define NULL
Definition: ftobjs.h:61
#define true
Definition: ftrandom.c:51
char Bool
Definition: ftraster.c:315
int Int
Definition: ftraster.c:307
unsigned int UInt
Definition: ftraster.c:308
backing_store_ptr info
[4]
Definition: jmemsys.h:161
JOCTET JCOEFPTR block
Definition: jsimd.h:109
typename C::const_iterator const_iterator
typename C::iterator iterator
QHighDpiScaling::Point position(T, QHighDpiScaling::Point::Kind)
Lock qt_scoped_lock(Mutex &mutex)
Definition: qlocking_p.h:94
Lock qt_unique_lock(Mutex &mutex)
Definition: qlocking_p.h:100
qsizetype fromUtf8(uchar b, OutputPtr &dst, InputPtr &src, InputPtr end)
int toUtf8(char16_t u, OutputPtr &dst, InputPtr &src, InputPtr end)
CaseSensitivity
Definition: qnamespace.h:1282
@ CaseInsensitive
Definition: qnamespace.h:1283
@ CaseSensitive
Definition: qnamespace.h:1284
constexpr char toHexUpper(uint value) noexcept
Definition: qtools_p.h:60
constexpr int fromHex(uint c) noexcept
Definition: qtools_p.h:70
QString eol
Definition: language.cpp:81
#define QString()
Definition: parse-defines.h:51
set set set set set set set macro pixldst1 abits if abits op else op endif endm macro pixldst2 abits if abits op else op endif endm macro pixldst4 abits if abits op else op endif endm macro pixldst0 abits op endm macro pixldst3 mem_operand op endm macro pixldst30 mem_operand op endm macro pixldst abits if abits elseif abits elseif abits elseif abits elseif abits pixldst0 abits else pixldst0 abits pixldst0 abits pixldst0 abits pixldst0 abits endif elseif abits else pixldst0 abits pixldst0 abits endif elseif abits else error unsupported bpp *numpix else pixst endif endm macro vuzp8 reg2 vuzp d d &reg2 endm macro vzip8 reg2 vzip d d &reg2 endm macro pixdeinterleave basereg basereg basereg basereg basereg endif endm macro pixinterleave basereg basereg basereg basereg basereg endif endm macro PF boost_increment endif if endif PF tst PF addne PF subne PF cmp ORIG_W if endif if endif if endif PF subge ORIG_W PF subges if endif if endif if endif endif endm macro cache_preload_simple endif if dst_r_bpp pld[DST_R, #(PREFETCH_DISTANCE_SIMPLE *dst_r_bpp/8)] endif if mask_bpp pld endif[MASK, #(PREFETCH_DISTANCE_SIMPLE *mask_bpp/8)] endif endif endm macro ensure_destination_ptr_alignment process_pixblock_tail_head if beq irp skip1 beq endif SRC MASK if dst_r_bpp DST_R else add endif PF add sub src_basereg pixdeinterleave mask_basereg pixdeinterleave dst_r_basereg process_pixblock_head pixblock_size cache_preload_simple process_pixblock_tail pixinterleave dst_w_basereg irp beq endif process_pixblock_tail_head tst beq irp if pixblock_size chunk_size tst beq pixld SRC pixld MASK if DST_R else pixld DST_R endif if
#define Q_FALLTHROUGH()
QList< QString > QStringList
Definition: qcontainerfwd.h:64
typedef QByteArray(EGLAPIENTRYP PFNQGSGETDISPLAYSPROC)()
EGLStreamKHR stream
EGLOutputLayerEXT EGLint EGLAttrib value
QT_BEGIN_INCLUDE_NAMESPACE typedef unsigned char uchar
Definition: qglobal.h:332
#define Q_AUTOTEST_EXPORT
Definition: qglobal.h:579
unsigned int uint
Definition: qglobal.h:334
#define Q_GLOBAL_STATIC(TYPE, NAME,...)
QList< QVariant > QVariantList
Definition: qjsonarray.h:50
#define qWarning
Definition: qlogging.h:179
GLenum type
Definition: qopengl.h:270
GLboolean GLboolean GLboolean b
GLsizei const GLfloat * v
[13]
GLuint64 key
GLboolean r
[2]
GLboolean GLboolean GLboolean GLboolean a
[7]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLuint index
[2]
GLuint GLuint end
GLdouble GLdouble GLdouble GLdouble top
GLsizei const GLuint * paths
GLboolean GLuint group
GLboolean enable
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLenum GLuint GLintptr offset
GLint ref
GLuint name
GLint first
GLfloat n
GLint GLsizei GLsizei GLenum format
struct _cl_event * event
Definition: qopenglext.h:2998
const GLubyte * c
Definition: qopenglext.h:12701
GLenum GLsizei len
Definition: qopenglext.h:3292
GLint limit
Definition: qopenglext.h:9975
GLdouble GLdouble GLdouble GLdouble q
Definition: qopenglext.h:259
GLsizei const GLchar *const * path
Definition: qopenglext.h:4283
GLuint64EXT * result
[6]
Definition: qopenglext.h:10932
GLdouble s
[6]
Definition: qopenglext.h:235
GLfloat GLfloat p
[1]
Definition: qopenglext.h:12698
#define Q_ASSERT(cond)
Definition: qrandom.cpp:84
#define Q_ASSERT_X(cond, x, msg)
Definition: qrandom.cpp:85
QHash< int, Path > PathHash
Definition: qsettings.cpp:125
QList< QConfFileCustomFormat > CustomFormatVector
Definition: qsettings.cpp:126
@ Space
Definition: qsettings.cpp:1482
@ Special
Definition: qsettings.cpp:1482
Q_DECLARE_TYPEINFO(QConfFileCustomFormat, Q_RELOCATABLE_TYPE)
QMap< QSettingsIniKey, QVariant > IniKeyMap
Definition: qsettings.cpp:1723
QHash< QString, QConfFile * > ConfFileHash
Definition: qsettings.cpp:112
#define FLUSH_CURRENT_SECTION()
QMap< QString, QSettingsIniSection > IniMap
Definition: qsettings.cpp:1735
QCache< QString, QConfFile > ConfFileCache
Definition: qsettings.cpp:113
#define k1
@ Q_RELOCATABLE_TYPE
Definition: qtypeinfo.h:156
QFile file
[0]
QVariant variant
[1]
map lowerBound(0)
QString dir
[11]
QGraphicsItem * item
view create()
QStringList::Iterator it
Qt::CaseSensitivity caseSensitivity
Definition: qsettings.cpp:108
QSettings::WriteFunc writeFunc
Definition: qsettings.cpp:107
QSettings::ReadFunc readFunc
Definition: qsettings.cpp:106
The QLatin1Char class provides an 8-bit ASCII/Latin-1 character.
Definition: qchar.h:53
@ Path
Definition: tst_qurl.cpp:3706
IUIAutomationTreeWalker __RPC__deref_out_opt IUIAutomationElement ** parent