📄 qsettings.cpp
字号:
if (readOnly) { QFileInfo fileInfo(confFile->name); if (confFile->size == fileInfo.size() && confFile->timeStamp == fileInfo.lastModified()) return; } /* Open the configuration file and try to use it using a named semaphore on Windows and an advisory lock on Unix-based systems. This protect us against other QSettings instances trying to access the same file from other threads or processes. As it stands now, the locking mechanism doesn't work for .plist files. */ QFile file(confFile->name); bool createFile = !file.exists(); if (!readOnly) file.open(QFile::ReadWrite); if (!file.isOpen()) file.open(QFile::ReadOnly);#ifdef Q_OS_WIN HANDLE semaphore = 0; static const int FileLockSemMax = 50; int numLocks = readOnly ? 1 : FileLockSemMax; if (file.isOpen()) { QString semName = QLatin1String("QSettings semaphore "); semName.append(file.fileName()); QT_WA( { semaphore = CreateSemaphoreW(0, FileLockSemMax, FileLockSemMax, reinterpret_cast<const wchar_t *>(semName.utf16())); } , { semaphore = CreateSemaphoreA(0, FileLockSemMax, FileLockSemMax, semName.toLocal8Bit()); } ); if (semaphore) { for (int i = 0; i < numLocks; ++i) WaitForSingleObject(semaphore, INFINITE); } else { setStatus(QSettings::AccessError); return; } }#else if (file.isOpen()) unixLock(file.handle(), readOnly ? F_RDLCK : F_WRLCK);#endif // If we have created the file, apply the file perms if (file.isOpen()) { if (createFile) { QFile::Permissions perms = QFile::ReadOwner|QFile::WriteOwner; if (!confFile->userPerms) perms |= QFile::ReadGroup|QFile::ReadOther; file.setPermissions(perms); } } /* We hold the lock. Let's reread the file if it has changed since last time we read it. */ QFileInfo fileInfo(confFile->name); bool mustReadFile = true; if (!readOnly) { mustReadFile = (confFile->size != fileInfo.size() || (confFile->size != 0 && confFile->timeStamp != fileInfo.lastModified())); } if (mustReadFile) { InternalSettingsMap newKeys; /* Files that we can't read (because of permissions or because they don't exist) are treated as empty files. */ if (file.isReadable() && fileInfo.size() != 0) {#ifdef Q_OS_MAC if (format == QSettings::NativeFormat) { ok = readPlistFile(confFile->name, &newKeys); } else#endif { if (format <= QSettings::IniFormat) { ok = readIniFile(file, &newKeys); } else { if (readFunc) { QSettings::SettingsMap tempNewKeys; ok = readFunc(file, tempNewKeys); if (ok) { QSettings::SettingsMap::const_iterator i = tempNewKeys.constBegin(); while (i != tempNewKeys.constEnd()) { newKeys.insert(QSettingsKey(i.key(), caseSensitivity), i.value()); ++i; } } } else { ok = false; } } } if (!ok) setStatus(QSettings::FormatError); } confFile->originalKeys = newKeys; confFile->size = fileInfo.size(); confFile->timeStamp = fileInfo.lastModified(); } /* We also need to save the file. We still hold the file lock, so everything is under control. */ if (!readOnly) { InternalSettingsMap mergedKeys = confFile->mergedKeyMap(); if (file.isWritable()) {#ifdef Q_OS_MAC if (format == QSettings::NativeFormat) { ok = writePlistFile(confFile->name, mergedKeys); } else#endif { file.seek(0); // shouldn't be necessary file.resize(0); if (format <= QSettings::IniFormat) { ok = writeIniFile(file, mergedKeys); } else { if (writeFunc) { QSettings::SettingsMap tempOriginalKeys; InternalSettingsMap::const_iterator i = mergedKeys.constBegin(); while (i != mergedKeys.constEnd()) { tempOriginalKeys.insert(i.key(), i.value()); ++i; } ok = writeFunc(file, tempOriginalKeys); } else { ok = false; } } } } else { ok = false; } if (ok) { confFile->originalKeys = mergedKeys; confFile->addedKeys.clear(); confFile->removedKeys.clear(); QFileInfo fileInfo(confFile->name); confFile->size = fileInfo.size(); confFile->timeStamp = fileInfo.lastModified(); } else { setStatus(QSettings::AccessError); } } /* Release the file lock. */#ifdef Q_OS_WIN if (semaphore != 0) { ReleaseSemaphore(semaphore, numLocks, 0); CloseHandle(semaphore); }#endif}bool QConfFileSettingsPrivate::readIniLine(QIODevice &device, QByteArray &line, int &len, int &equalsCharPos){#define MAYBE_GROW() \ if (pos + 4 > line.size()) { \ line.resize(pos << 1); \ data = line.data(); \ } char *data = line.data(); char ch, ch2; int pos = 0; equalsCharPos = -1; while (device.getChar(&ch)) { process_ch: MAYBE_GROW(); switch (ch) { case '"': data[pos++] = '"'; while (device.getChar(&ch) && ch != '"') { MAYBE_GROW(); if (static_cast<signed char>(ch) == -1) goto end; if (ch == '\\') { data[pos++] = '\\'; if (!device.getChar(&ch)) goto end; } data[pos++] = ch; } data[pos++] = '"'; break; case ' ': case '\t': if (pos > 0) data[pos++] = ch; break; case '\n': case '\r': process_newline: /* According to the specs, a line ends with CF, LF, CR+LF, or LF+CR. In practice, this is irrelevant and the ungetch() call is expensive, so let's not do it. */#if 0 if (!device.getChar(&ch2)) goto end; if ((ch2 != '\n' && ch2 != '\r') || ch == ch2) device.ungetChar(ch2);#endif if (pos > 0) goto end; break; case '\\': if (!device.getChar(&ch)) goto end; if (ch == '\n' || ch == '\r') { if (device.getChar(&ch2)) { if ((ch2 != '\n' && ch2 != '\r') || ch == ch2) { ch = ch2; goto process_ch; } } } else { data[pos++] = '\\'; data[pos++] = ch; } break; case ';': while (device.getChar(&ch)) { if (ch == '\n' || ch == '\r') goto process_newline; } break; case '=': if (equalsCharPos == -1) { while (pos > 0 && (ch = data[pos - 1]) == ' ' || ch == '\t') --pos; equalsCharPos = pos; } data[pos++] = '='; break; default: data[pos++] = ch; } }end: data[pos] = '\0'; len = pos; return pos > 0;}/* Returns false on parse error. However, as many keys are read as possible, so if the user doesn't check the status he will get the most out of the file anyway.*/bool QConfFileSettingsPrivate::readIniFile(QIODevice &device, InternalSettingsMap *map){ QString currentSection; bool currentSectionIsLowercase = true; QByteArray line; line.resize(512); int equalsCharPos; int len; bool ok = true; while (readIniLine(device, line, len, equalsCharPos)) { if (line.at(0) == '[') { // this is a section QByteArray iniSection; int idx = line.indexOf(']'); if (idx == -1) { ok = false; iniSection = line.mid(1); } else { iniSection = line.mid(1, idx - 1); } iniSection = iniSection.trimmed(); if (qstricmp(iniSection, "general") == 0) { currentSection.clear(); } else if (qstricmp(iniSection, "%general") == 0) { currentSection = QLatin1String("general"); currentSection += QLatin1Char('/'); } else { currentSection.clear(); currentSectionIsLowercase = iniUnescapedKey(iniSection, 0, iniSection.size(), currentSection); currentSection += QLatin1Char('/'); } } else { if (equalsCharPos < 1) { ok = false; continue; } QString key = currentSection; bool keyIsLowercase = (iniUnescapedKey(line, 0, equalsCharPos, key) && currentSectionIsLowercase); QString strValue; strValue.reserve(len - equalsCharPos); QStringList *strListValue = iniUnescapedStringList(line, equalsCharPos + 1, len, strValue); QVariant variant; if (strListValue) { variant = stringListToVariantList(*strListValue); delete strListValue; } else { variant = stringToVariant(strValue); } /* We try to avoid the expensive toLower() call in QSettingsKey by passing Qt::CaseSensitive when the key is already in lowercase. */ map->insert(QSettingsKey(key, keyIsLowercase ? Qt::CaseSensitive : Qt::CaseInsensitive), variant); } } return ok;}bool QConfFileSettingsPrivate::writeIniFile(QIODevice &device, const InternalSettingsMap &map){ typedef QMap<QString, QVariantMap> IniMap; IniMap iniMap; IniMap::const_iterator i;#ifdef Q_OS_WIN const char * const eol = "\r\n";#else const char eol = '\n';#endif for (InternalSettingsMap::const_iterator j = map.constBegin(); j != map.constEnd(); ++j) { QString section; QString key = j.key().realKey(); int slashPos; if ((slashPos = key.indexOf(QLatin1Char('/'))) != -1) { section = key.left(slashPos); key.remove(0, slashPos + 1); } iniMap[section][key] = j.value(); } bool writeError = false; for (i = iniMap.constBegin(); !writeError && i != iniMap.constEnd(); ++i) { QByteArray realSection; iniEscapedKey(i.key(), realSection); if (realSection.isEmpty()) { realSection = "[General]"; } else if (qstricmp(realSection, "general") == 0) { realSection = "[%General]"; } else { realSection.prepend('['); realSection.append(']'); } if (i != iniMap.constBegin()) realSection.prepend(eol); realSection += eol; device.write(realSection); const QVariantMap &ents = i.value(); for (QVariantMap::const_iterator j = ents.constBegin(); j != ents.constEnd(); ++j) { QByteArray block; iniEscapedKey(j.key(), block); block += '='; const QVariant &value = j.value(); /* The size() != 1 trick is necessary because QVariant(QString("foo")).toList() returns an empty list, not a list containing "foo". */ if (value.type() == QVariant::StringList || (value.type() == QVariant::List && value.toList().size() != 1)) { iniEscapedStringList(variantListToStringList(value.toList()), block); } else {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -