From 72ea4a16988f1c28e97064222e722f19bc31b3a6 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Enar=20V=C3=A4ikene?= Date: Wed, 30 Nov 2011 14:26:14 +0200 Subject: [PATCH] Changed the Common::IniFile class to work with 7-bit character INI files only. * Strings and byte arrays are now escaped; * Strings and byte arrays can now be in single or double quotes; makes it possible to have leading and trailing spaces. * When saving string or byte array values with leading or trailing spaces, automatically adds double quotes. --- src/libs/Common/config.cpp | 4 +- src/libs/Common/inifile.cpp | 114 ++++++++++++++++++++++++++---------- src/libs/Common/inifile.h | 6 +- src/libs/Common/inifile_p.h | 23 +++++--- src/libs/Common/version.h | 4 +- 5 files changed, 103 insertions(+), 48 deletions(-) diff --git a/src/libs/Common/config.cpp b/src/libs/Common/config.cpp index 610dd74..c4f0997 100644 --- a/src/libs/Common/config.cpp +++ b/src/libs/Common/config.cpp @@ -123,7 +123,7 @@ QVariant Config::getValue(QString const & paramName, QVariant const & defaultVal } // Read the value - return ini->getValue(name, defaultValue); + return ini->getValue(name.toLocal8Bit(), defaultValue); } bool Config::setValue(QString const & paramName, QVariant const & value, bool commit) @@ -198,7 +198,7 @@ bool Config::writeValue(QString const & paramName, QVariant const & value) } // Write the value - if (!ini->setValue(name, value)) + if (!ini->setValue(name.toLocal8Bit(), value)) return false; return true; diff --git a/src/libs/Common/inifile.cpp b/src/libs/Common/inifile.cpp index 14a47ee..838ff72 100644 --- a/src/libs/Common/inifile.cpp +++ b/src/libs/Common/inifile.cpp @@ -56,12 +56,12 @@ QString IniFile::errorString() const return d->errorString(); } -QVariant IniFile::getValue(QString const & paramName, QVariant const & defaultValue) +QVariant IniFile::getValue(QByteArray const & paramName, QVariant const & defaultValue) { return d->getValue(paramName, defaultValue); } -bool IniFile::setValue(QString const & paramName, QVariant const & value) +bool IniFile::setValue(QByteArray const & paramName, QVariant const & value) { return d->setValue(paramName, value); } @@ -99,7 +99,7 @@ IniFileImpl::~IniFileImpl() void IniFileImpl::updateCache(quint64 pos, qint64 diff) { // Walk through all the sections in the cache - QHash >::const_iterator it; + QHash >::const_iterator it; for (it = mCache.constBegin(); it != mCache.constEnd(); ++it) { QExplicitlySharedDataPointer sectionObject = *it; @@ -108,7 +108,7 @@ void IniFileImpl::updateCache(quint64 pos, qint64 diff) sectionObject->filePos += diff; // Update individual values in the section that come after the current file offset - QHash >::const_iterator it1; + QHash >::const_iterator it1; for (it1 = sectionObject->values.constBegin(); it1 != sectionObject->values.constEnd(); ++it1) { QExplicitlySharedDataPointer valueObject = *it1; if (valueObject->filePos > pos) @@ -117,7 +117,7 @@ void IniFileImpl::updateCache(quint64 pos, qint64 diff) } } -QExplicitlySharedDataPointer IniFileImpl::getSection(QFile & file, QString const & sectionName) +QExplicitlySharedDataPointer IniFileImpl::getSection(QFile & file, QByteArray const & sectionName) { // Check for external modifications QFileInfo fi(file); @@ -128,7 +128,7 @@ QExplicitlySharedDataPointer IniFileImpl::getSection(QFile & fil } // Look for the section in the cache first - QHash >::const_iterator it = mCache.constFind(sectionName.toLower()); + QHash >::const_iterator it = mCache.constFind(sectionName.toLower()); if (it != mCache.constEnd()) { // Found in the cache if (mValid) @@ -138,7 +138,7 @@ QExplicitlySharedDataPointer IniFileImpl::getSection(QFile & fil // Read the INI file and look for the section while (mValid && !file.atEnd()) { - QString line = file.readLine().trimmed(); + QByteArray line = file.readLine().trimmed(); // Ignore the line if it is empty, a comment or not a section name if (line.isEmpty() || line.startsWith(';') || line.startsWith('#') || !line.startsWith('[')) @@ -150,7 +150,7 @@ QExplicitlySharedDataPointer IniFileImpl::getSection(QFile & fil continue; // Is this the section that we are looking for? - if (line.mid(1, idx - 1).compare(sectionName, Qt::CaseInsensitive) == 0) { + if (qstricmp(line.mid(1, idx - 1).constData(), sectionName.constData()) == 0) { // Create the section object and add to the cache QExplicitlySharedDataPointer sectionObject(new IniFileSection(file.pos())); sectionObject->name = sectionName.toLower(); @@ -166,10 +166,10 @@ QExplicitlySharedDataPointer IniFileImpl::getSection(QFile & fil return QExplicitlySharedDataPointer(); } -QExplicitlySharedDataPointer IniFileImpl::getParameter(QFile & file, IniFileSection & section, QString const & paramName) +QExplicitlySharedDataPointer IniFileImpl::getParameter(QFile & file, IniFileSection & section, QByteArray const & paramName) { // Look for the parameter in the cache first - QHash >::const_iterator it = section.values.constFind(paramName.toLower()); + QHash >::const_iterator it = section.values.constFind(paramName.toLower()); if (it != section.values.constEnd()) { // Found it in the cache if (mValid) @@ -183,7 +183,7 @@ QExplicitlySharedDataPointer IniFileImpl::getParameter(QFile & fil // Current file position quint64 currentPos = file.pos(); - QString line = file.readLine().trimmed(); + QByteArray line = file.readLine().trimmed(); // Ignore the line if it is empty or a comment if (line.isEmpty() || line.startsWith(';') || line.startsWith('#')) @@ -202,8 +202,8 @@ QExplicitlySharedDataPointer IniFileImpl::getParameter(QFile & fil if (idx == -1) continue; - QString name = line.mid(0, idx).trimmed().toLower(); - QString value = line.mid(idx + 1).trimmed(); + QByteArray name = line.mid(0, idx).trimmed().toLower(); + QByteArray value = line.mid(idx + 1).trimmed(); // Check for the 'windows:' or 'linux:' prefix in the parameter name bool thisOsOnly = false; @@ -226,7 +226,7 @@ QExplicitlySharedDataPointer IniFileImpl::getParameter(QFile & fil // If the parameter value is not in the cache, add it to the cache QExplicitlySharedDataPointer valueObject; - QHash >::const_iterator it = section.values.constFind(name); + QHash >::const_iterator it = section.values.constFind(name); if (it == section.values.constEnd()) { valueObject = new IniFileValue(currentPos); valueObject->name = name; @@ -243,7 +243,7 @@ QExplicitlySharedDataPointer IniFileImpl::getParameter(QFile & fil } // Is this the parameter vwe are looking for? - if (name.compare(paramName, Qt::CaseInsensitive) == 0) { + if (qstricmp(name.constData(), paramName.constData()) == 0) { // Rewind to the beginning of the line file.seek(currentPos); @@ -256,7 +256,7 @@ QExplicitlySharedDataPointer IniFileImpl::getParameter(QFile & fil return QExplicitlySharedDataPointer(); } -QVariant IniFileImpl::getValue(QString const & paramName, QVariant const & defaultValue) +QVariant IniFileImpl::getValue(QByteArray const & paramName, QVariant const & defaultValue) { // Locate the '/' character that separates section names from key names int idx = paramName.lastIndexOf('/'); @@ -264,8 +264,8 @@ QVariant IniFileImpl::getValue(QString const & paramName, QVariant const & defau return defaultValue; // Separate section and key names - QString section = paramName.left(idx); - QString key = paramName.mid(idx + 1); + QByteArray section = paramName.left(idx); + QByteArray key = paramName.mid(idx + 1); // Open the file QFile f(mFileName); @@ -289,10 +289,38 @@ QVariant IniFileImpl::getValue(QString const & paramName, QVariant const & defau if (f.isOpen()) f.close(); - return toVariant(valueObject->paramValue, defaultValue); + // Return the cached value if it is already set and the type is the same than the default value type + if (valueObject->value.isValid() && (!defaultValue.isValid() || valueObject->value.type() == defaultValue.type())) + return valueObject->value; + + // Convert to the proper type + if (defaultValue.type() == QVariant::ByteArray || defaultValue.type() == QVariant::String) { + // Remove single and double quotes + QByteArray v = valueObject->paramValue; + if (v.startsWith('\"')) { + v.remove(0, 1); + if (v.endsWith('\"')) + v.remove(v.size() - 1, 1); + } + else if (v.startsWith('\'')) { + v.remove(0, 1); + if (v.endsWith('\'')) + v.remove(v.size() - 1, 1); + } + + // Convert from the escaped character array + if (defaultValue.type() == QVariant::String) + valueObject->value = QVariant(strFromEscapedCharArray(v)); + else + valueObject->value = QVariant(binFromEscapedCharArray(v)); + } + else + valueObject->value = toVariant(valueObject->paramValue, defaultValue); + + return valueObject->value; } -bool IniFileImpl::setValue(QString const & paramName, QVariant const & value) +bool IniFileImpl::setValue(QByteArray const & paramName, QVariant const & value) { // Locate the '/' character that separates section names from key names int idx = paramName.lastIndexOf('/', -1); @@ -300,29 +328,49 @@ bool IniFileImpl::setValue(QString const & paramName, QVariant const & value) return false; // Separate section and key names - QString section = paramName.left(idx).toLower(); - QString key = paramName.mid(idx + 1).toLower(); + QByteArray section = paramName.left(idx).toLower(); + QByteArray key = paramName.mid(idx + 1).toLower(); // Format the value depending on the type - QString valueString; + QByteArray valueString; switch (value.type()) { case QVariant::UInt: - valueString = "0x" + QString::number(value.toUInt(), 16); + valueString = QByteArray("0x").append(QByteArray::number(value.toUInt(), 16)); break; case QVariant::Int: - valueString = QString::number(value.toInt()); + valueString = QByteArray::number(value.toInt()); break; case QVariant::Double: - valueString = QString::number(value.toDouble(), 'f'); + valueString = QByteArray::number(value.toDouble(), 'f'); break; case QVariant::Bool: valueString = value.toBool() ? "true" : "false"; break; - case QVariant::Char: - valueString = value.toChar(); + case QVariant::Char: { + QChar c = value.toChar(); + printf("c.unicode() = %u\n", c.unicode()); + if (c.unicode() < 32 || c.unicode() >= 127) + valueString = QByteArray("\\0x").append(QByteArray::number(c.unicode(), 16)); + else + valueString = QByteArray(1, (char const)c.unicode()); + break; + } + case QVariant::ByteArray: + valueString = binToEscapedCharArray(value.toByteArray()); + if (valueString.startsWith(' ') || valueString.endsWith(' ')) { + valueString.insert(0, '\"'); + valueString.append('\"'); + } + break; + case QVariant::String: + valueString = strToEscapedCharArray(value.toString()); + if (valueString.startsWith(' ') || valueString.endsWith(' ')) { + valueString.insert(0, '\"'); + valueString.append('\"'); + } break; default: - valueString = value.toString(); + valueString = value.toString().toLatin1(); } // Open the file @@ -343,7 +391,7 @@ bool IniFileImpl::setValue(QString const & paramName, QVariant const & value) if (!sectionObject) { // Write the new section to the INI file (the file is already positioned at the end) - if (f.write(QString("[%1]" EOL).arg(section).toLocal8Bit()) == -1) { + if (f.write(QString("[%1]" EOL).arg(section.constData()).toLatin1()) == -1) { mErrorString = f.errorString(); mValid = false; EVAF_ERROR("Failed to write to the INI file %s : %s", qPrintable(mFileName), qPrintable(mErrorString)); @@ -358,7 +406,7 @@ bool IniFileImpl::setValue(QString const & paramName, QVariant const & value) mCache.insert(section.toLower(), sectionObject); // Write the parameter value to the INI file - if (f.write(QString("%1 = %2" EOL).arg(key).arg(valueString).toLocal8Bit()) == -1) { + if (f.write(QString("%1 = %2" EOL).arg(key.constData()).arg(valueString.constData()).toLatin1()) == -1) { mErrorString = f.errorString(); mValid = false; EVAF_ERROR("Failed to write to the INI file %s : %s", qPrintable(mFileName), qPrintable(mErrorString)); @@ -369,6 +417,7 @@ bool IniFileImpl::setValue(QString const & paramName, QVariant const & value) QExplicitlySharedDataPointer valueObject(new IniFileValue(currentPos)); valueObject->name = key; valueObject->paramValue = valueString; + valueObject->value = value; sectionObject->values.insert(key, valueObject); } @@ -423,7 +472,7 @@ bool IniFileImpl::setValue(QString const & paramName, QVariant const & value) // Rewind to the original position and write the new parameter value f.seek(currentPos); - if (f.write(QString("%1%2 = %3" EOL).arg(prefix).arg(key).arg(valueString).toLocal8Bit()) == -1) { + if (f.write(QString("%1%2 = %3" EOL).arg(prefix).arg(key.constData()).arg(valueString.constData()).toLatin1()) == -1) { mErrorString = f.errorString(); mValid = false; EVAF_ERROR("Failed to write to the INI file %s : %s", qPrintable(mFileName), qPrintable(mErrorString)); @@ -459,6 +508,7 @@ bool IniFileImpl::setValue(QString const & paramName, QVariant const & value) // Update the parameter value in the internal cache valueObject->paramValue = valueString; + valueObject->value = value; } diff --git a/src/libs/Common/inifile.h b/src/libs/Common/inifile.h index 21a1bc4..2ebe1c1 100644 --- a/src/libs/Common/inifile.h +++ b/src/libs/Common/inifile.h @@ -59,7 +59,7 @@ namespace Internal { * of different data types: * * @li Bool - '0', 'false', 'off', 'no' are equal to false and '1', 'true', 'on', 'yes' are equal to true; - * @li Char - a single character or an ASCII code as '\0NNN' (oct) or '\0xNN' (hex); + * @li Char - a single character or an UTF-16 code as '\0NNNNNN' (oct) or '\0xNNNN' (hex); * @li Date - date string in the ISO 8601 format YYYY-MM-DD; * @li DateTime - date and time string in the ISO 8601 format YYY-MM-DDTHH:MM:SSTZD; * @li Double - the decimal point is always '.' regardless of the locale; @@ -119,7 +119,7 @@ public: * * @sa eVaf::Common::toVariant() */ - QVariant getValue(QString const & paramName, QVariant const & defaultValue = QVariant::Invalid); + QVariant getValue(QByteArray const & paramName, QVariant const & defaultValue = QVariant::Invalid); /** * Writes a value to the INI file. @@ -134,7 +134,7 @@ public: * The method returns true if the parameter value was written into the INI file and false if not. Use the errorString() method * to get a human-readable error string if writing to the INI file fails. */ - bool setValue(QString const & paramName, QVariant const & value); + bool setValue(QByteArray const & paramName, QVariant const & value); private: diff --git a/src/libs/Common/inifile_p.h b/src/libs/Common/inifile_p.h index b782627..ffb7a1e 100644 --- a/src/libs/Common/inifile_p.h +++ b/src/libs/Common/inifile_p.h @@ -57,12 +57,17 @@ public: /** * Key name of the parameter */ - QString name; + QByteArray name; /** * Value from the INI file */ - QString paramValue; + QByteArray paramValue; + + /** + * Value converted to the final type (defaults to QVariant::Invalid + */ + QVariant value; /** * Flag indicating that this value is valid on this OS only @@ -93,14 +98,14 @@ public: /** * Name of the section */ - QString name; + QByteArray name; /** * List of all the known parameter values in this section * * The key to the hash table is the name of the key for the parameters value. */ - QHash > values; + QHash > values; }; @@ -115,9 +120,9 @@ public: ~IniFileImpl(); - QVariant getValue(QString const & paramName, QVariant const & defaultValue); + QVariant getValue(QByteArray const & paramName, QVariant const & defaultValue); - bool setValue(QString const & paramName, QVariant const & value); + bool setValue(QByteArray const & paramName, QVariant const & value); inline bool isValid() const { return mValid; } @@ -145,7 +150,7 @@ private: // Members * * The key to the hash table is the name of the section. */ - QHash > mCache; + QHash > mCache; /// When was the INI file modified. QDateTime mLastModified; @@ -178,7 +183,7 @@ private: /// Methods * The file object is expected to be opened if the mValid flag is true. If the mValid flag is false, looks * only in the cache. */ - QExplicitlySharedDataPointer getSection(QFile & file, QString const & sectionName); + QExplicitlySharedDataPointer getSection(QFile & file, QByteArray const & sectionName); /** * Looks for a parameter in the INI file @@ -195,7 +200,7 @@ private: /// Methods * The file object is expected to be opened if the mValid flag is true. If the mValid flag is false, looks * only in the cache. */ - QExplicitlySharedDataPointer getParameter(QFile & file, IniFileSection & section, QString const & paramName); + QExplicitlySharedDataPointer getParameter(QFile & file, IniFileSection & section, QByteArray const & paramName); }; diff --git a/src/libs/Common/version.h b/src/libs/Common/version.h index e6068b9..fb1c67f 100644 --- a/src/libs/Common/version.h +++ b/src/libs/Common/version.h @@ -25,12 +25,12 @@ /** * Module/library version number in the form major,minor,release,build */ -#define VER_FILE_VERSION 0,2,2,9 +#define VER_FILE_VERSION 0,2,2,10 /** * Module/library version number in the string format (shall end with \0) */ -#define VER_FILE_VERSION_STR "0.2.2.9\0" +#define VER_FILE_VERSION_STR "0.2.2.10\0" /** * Module/library name (shall end with \0) -- 2.47.0