summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/corelib/io/qsettings.cpp6
-rw-r--r--src/corelib/io/qsettings_mac.cpp20
-rw-r--r--src/corelib/io/qsettings_win.cpp13
-rw-r--r--src/corelib/io/qsettings_winrt.cpp4
-rw-r--r--tests/auto/corelib/io/qsettings/tst_qsettings.cpp50
5 files changed, 76 insertions, 17 deletions
diff --git a/src/corelib/io/qsettings.cpp b/src/corelib/io/qsettings.cpp
index 9e0e6c2769..d1ae14490c 100644
--- a/src/corelib/io/qsettings.cpp
+++ b/src/corelib/io/qsettings.cpp
@@ -413,7 +413,9 @@ QString QSettingsPrivate::variantToString(const QVariant &v)
case QVariant::Double:
case QVariant::KeySequence: {
result = v.toString();
- if (result.startsWith(QLatin1Char('@')))
+ if (result.contains(QChar::Null))
+ result = QLatin1String("@String(") + result + QLatin1Char(')');
+ else if (result.startsWith(QLatin1Char('@')))
result.prepend(QLatin1Char('@'));
break;
}
@@ -489,6 +491,8 @@ QVariant QSettingsPrivate::stringToVariant(const QString &s)
if (s.endsWith(QLatin1Char(')'))) {
if (s.startsWith(QLatin1String("@ByteArray("))) {
return QVariant(s.midRef(11, s.size() - 12).toLatin1());
+ } else if (s.startsWith(QLatin1String("@String("))) {
+ return QVariant(s.midRef(8, s.size() - 9).toString());
} else if (s.startsWith(QLatin1String("@Variant("))
|| s.startsWith(QLatin1String("@DateTime("))) {
#ifndef QT_NO_DATASTREAM
diff --git a/src/corelib/io/qsettings_mac.cpp b/src/corelib/io/qsettings_mac.cpp
index e0b317b4c2..0b039f73dc 100644
--- a/src/corelib/io/qsettings_mac.cpp
+++ b/src/corelib/io/qsettings_mac.cpp
@@ -208,7 +208,14 @@ static QCFType<CFPropertyListRef> macValue(const QVariant &value)
case QVariant::String:
string_case:
default:
- result = QCFString::toCFStringRef(QSettingsPrivate::variantToString(value));
+ QString string = QSettingsPrivate::variantToString(value);
+ if (string.contains(QChar::Null)) {
+ QByteArray ba = string.toUtf8();
+ result = CFDataCreate(kCFAllocatorDefault, reinterpret_cast<const UInt8 *>(ba.data()),
+ CFIndex(ba.size()));
+ } else {
+ result = QCFString::toCFStringRef(string);
+ }
}
return result;
}
@@ -261,8 +268,17 @@ static QVariant qtValue(CFPropertyListRef cfvalue)
return (bool)CFBooleanGetValue(static_cast<CFBooleanRef>(cfvalue));
} else if (typeId == CFDataGetTypeID()) {
CFDataRef cfdata = static_cast<CFDataRef>(cfvalue);
- return QByteArray(reinterpret_cast<const char *>(CFDataGetBytePtr(cfdata)),
+ QByteArray byteArray = QByteArray(reinterpret_cast<const char *>(CFDataGetBytePtr(cfdata)),
CFDataGetLength(cfdata));
+
+ // Fast-path for QByteArray, so that we don't have to go
+ // though the expensive and lossy conversion via UTF-8.
+ if (!byteArray.startsWith('@'))
+ return byteArray;
+
+ const QString str = QString::fromUtf8(byteArray.constData(), byteArray.size());
+ return QSettingsPrivate::stringToVariant(str);
+
} else if (typeId == CFDictionaryGetTypeID()) {
CFDictionaryRef cfdict = static_cast<CFDictionaryRef>(cfvalue);
CFTypeID arrayTypeId = CFArrayGetTypeID();
diff --git a/src/corelib/io/qsettings_win.cpp b/src/corelib/io/qsettings_win.cpp
index da0c4c3c14..f6ad182c37 100644
--- a/src/corelib/io/qsettings_win.cpp
+++ b/src/corelib/io/qsettings_win.cpp
@@ -649,15 +649,6 @@ void QWinSettingsPrivate::remove(const QString &uKey)
}
}
-static bool stringContainsNullChar(const QString &s)
-{
- for (int i = 0; i < s.length(); ++i) {
- if (s.at(i).unicode() == 0)
- return true;
- }
- return false;
-}
-
void QWinSettingsPrivate::set(const QString &uKey, const QVariant &value)
{
if (writeHandle() == 0) {
@@ -686,7 +677,7 @@ void QWinSettingsPrivate::set(const QString &uKey, const QVariant &value)
QStringList l = variantListToStringList(value.toList());
QStringList::const_iterator it = l.constBegin();
for (; it != l.constEnd(); ++it) {
- if ((*it).length() == 0 || stringContainsNullChar(*it)) {
+ if ((*it).length() == 0 || it->contains(QChar::Null)) {
type = REG_BINARY;
break;
}
@@ -730,7 +721,7 @@ void QWinSettingsPrivate::set(const QString &uKey, const QVariant &value)
// If the string does not contain '\0', we can use REG_SZ, the native registry
// string type. Otherwise we use REG_BINARY.
QString s = variantToString(value);
- type = stringContainsNullChar(s) ? REG_BINARY : REG_SZ;
+ type = s.contains(QChar::Null) ? REG_BINARY : REG_SZ;
if (type == REG_BINARY) {
regValueBuff = QByteArray((const char*)s.utf16(), s.length() * 2);
} else {
diff --git a/src/corelib/io/qsettings_winrt.cpp b/src/corelib/io/qsettings_winrt.cpp
index 85ef64cbd4..5ab1133ef3 100644
--- a/src/corelib/io/qsettings_winrt.cpp
+++ b/src/corelib/io/qsettings_winrt.cpp
@@ -396,7 +396,7 @@ void QWinRTSettingsPrivate::set(const QString &uKey, const QVariant &value)
QStringList::const_iterator it = l.constBegin();
bool containsNull = false;
for (; it != l.constEnd(); ++it) {
- if ((*it).length() == 0 || it->indexOf(QChar::Null) != -1) {
+ if ((*it).length() == 0 || it->contains(QChar::Null)) {
// We can only store as binary
containsNull = true;
break;
@@ -439,7 +439,7 @@ void QWinRTSettingsPrivate::set(const QString &uKey, const QVariant &value)
break;
default: {
const QString s = variantToString(value);
- if (s.indexOf(QChar::Null) != -1) {
+ if (s.contains(QChar::Null)) {
hr = valueStatics->CreateUInt8Array(s.length() * 2, (BYTE*) s.utf16(), &val);
} else {
HStringReference ref((const wchar_t*)s.utf16(), s.size());
diff --git a/tests/auto/corelib/io/qsettings/tst_qsettings.cpp b/tests/auto/corelib/io/qsettings/tst_qsettings.cpp
index 19155cc3ad..f489b9b1d3 100644
--- a/tests/auto/corelib/io/qsettings/tst_qsettings.cpp
+++ b/tests/auto/corelib/io/qsettings/tst_qsettings.cpp
@@ -162,6 +162,8 @@ private slots:
void testByteArray();
void iniCodec();
void bom();
+ void embeddedZeroByte_data();
+ void embeddedZeroByte();
private:
void cleanupTestFiles();
@@ -655,7 +657,6 @@ void tst_QSettings::testByteArray_data()
#ifndef QT_NO_COMPRESS
QTest::newRow("compressed") << qCompress(bytes);
#endif
- QTest::newRow("with \\0") << bytes + '\0' + bytes;
}
void tst_QSettings::testByteArray()
@@ -706,6 +707,53 @@ void tst_QSettings::bom()
QVERIFY(allkeys.contains("section2/foo2"));
}
+void tst_QSettings::embeddedZeroByte_data()
+{
+ QTest::addColumn<QVariant>("value");
+
+ QByteArray bytes("hello\0world", 11);
+
+ QTest::newRow("bytearray\\0") << QVariant(bytes);
+ QTest::newRow("string\\0") << QVariant(QString::fromLatin1(bytes.data(), bytes.size()));
+
+ bytes = QByteArray("@String(");
+
+ QTest::newRow("@bytearray") << QVariant(bytes);
+ QTest::newRow("@string") << QVariant(QString(bytes));
+
+ bytes = QByteArray("@String(\0test", 13);
+
+ QTest::newRow("@bytearray\\0") << QVariant(bytes);
+ QTest::newRow("@string\\0") << QVariant(QString::fromLatin1(bytes.data(), bytes.size()));
+}
+
+void tst_QSettings::embeddedZeroByte()
+{
+ QFETCH(QVariant, value);
+ {
+ QSettings settings("QtProject", "tst_qsettings");
+ settings.setValue(QTest::currentDataTag(), value);
+ }
+ {
+ QSettings settings("QtProject", "tst_qsettings");
+ QVariant outValue = settings.value(QTest::currentDataTag());
+
+ switch (value.type()) {
+ case QVariant::ByteArray:
+ QCOMPARE(outValue.toByteArray(), value.toByteArray());
+ break;
+ case QVariant::String:
+ QCOMPARE(outValue.toString(), value.toString());
+ break;
+ default:
+ Q_UNREACHABLE();
+ }
+
+ if (value.toByteArray().contains(QChar::Null))
+ QVERIFY(outValue.toByteArray().contains(QChar::Null));
+ }
+}
+
void tst_QSettings::testErrorHandling_data()
{
QTest::addColumn<int>("filePerms"); // -1 means file should not exist