From kde-core-devel Mon Sep 17 01:39:33 2007 From: David Jarvie Date: Mon, 17 Sep 2007 01:39:33 +0000 To: kde-core-devel Subject: Re: KConfigGroup read/write bug for QByteArray Message-Id: <200709170239.33527.lists () astrojar ! org ! uk> X-MARC-Message: https://marc.info/?l=kde-core-devel&m=118999316600234 MIME-Version: 1 Content-Type: multipart/mixed; boundary="--Boundary-00=_Vrd7GuVz+dknYNZ" --Boundary-00=_Vrd7GuVz+dknYNZ Content-Type: text/plain; charset="iso-8859-15" Content-Transfer-Encoding: 7bit Content-Disposition: inline On Sunday 16 September 2007 14:41:28 Matt Rogers wrote: > On Sunday 16 September 2007 07:41, David Jarvie wrote: > > Using KConfigGroup::writeEntry() to write a QByteArray and then > > KConfigGroup::readEntry() to read it back in again can result in a value > > which is different from the original value, because the value written to > > the config file is converted to UTF8 when it is read back, so that all > > byte values >= 0x7F are changed to multi-byte values. > > > > If this is the desired behaviour (which I doubt), it's difficult to > > convert back from UTF8 since calling QString::fromUtf8 truncates the > > value as soon as it encounters a null byte. In data arrays, null bytes > > are common. > > Can you provide a patch? Then we can discuss your proposal based on the > technical merits of it rather than just sitting in our chairs wondering to > ourselves how it would actually work and whether or not we'd like it. It turns out that the bug actually lies in KConfigGroup::writeEntry(), and that all that is required is for a QByteArray not to be converted to UTF8 before being written. I attach a patch to fix it, and to add a test case to the unit test. -- David Jarvie. KAlarm author and maintainer. http://www.astrojar.org.uk/kalarm --Boundary-00=_Vrd7GuVz+dknYNZ Content-Type: text/x-diff; charset="iso-8859-15"; name="bytearray.diff" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="bytearray.diff" Index: tests/kconfigtest.cpp =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =2D-- tests/kconfigtest.cpp (revision 708428) +++ tests/kconfigtest.cpp (working copy) @@ -39,6 +39,7 @@ #define STRINGENTRY5 " " #define STRINGENTRY6 "" #define UTF8BITENTRY "Hello =C3=A4=C3=B6=C3=BC" +#define BYTEARRAYENTRY QByteArray( "\x00\xff\x7f\x3c abc\x00\x00", 10 ) #define ESCAPEKEY " []\0017[]=3D=3D]" #define ESCAPEENTRY "[]\170[]]=3D3=3D]\\] " #define DOUBLEENTRY 123456.78912345 @@ -72,6 +73,7 @@ QCOMPARE( data.size(), 12 ); // the source file is in utf8 QCOMPARE( QString::fromUtf8(data).length(), 9 ); cg.writeEntry( "Test", QVariant( data ) ); // passing "data" converts it= to char* and KConfigBase calls fromLatin1! + cg.writeEntry( "bytearrayEntry", BYTEARRAYENTRY ); cg.writeEntry( ESCAPEKEY, ESCAPEENTRY ); cg.writeEntry( "Test2", ""); cg.writeEntry( "stringEntry1", STRINGENTRY1 ); @@ -207,6 +209,7 @@ =20 sc3 =3D KConfigGroup(&sc2, "Hello"); QCOMPARE( sc3.readEntry( "Test", QByteArray() ), QByteArray( UTF8BITENTR= Y ) ); + QCOMPARE( sc3.readEntry( "bytearrayEntry", QByteArray() ), BYTEARRAYENTR= Y ); QCOMPARE( sc3.readEntry( ESCAPEKEY ), QString( ESCAPEENTRY ) ); QCOMPARE( sc3.readEntry( "Test", QString() ), QString::fromUtf8( UTF8BIT= ENTRY ) ); QCOMPARE( sc3.readEntry("Test2", QString("Fietsbel")).isEmpty(), true ); Index: config/kconfiggroup.cpp =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =2D-- config/kconfiggroup.cpp (revision 708428) +++ config/kconfiggroup.cpp (working copy) @@ -681,6 +681,31 @@ void KConfigGroup::writeEntry( const char *pKey, const QString& value, KConfigBase::WriteConfigFlags pFlags ) { + writeEntry( pKey, value.toUtf8(), pFlags ); +} + +void KConfigGroup::writeEntry( const QString& pKey, const QStringList &val= ue, + char sep, + WriteConfigFlags pFlags ) +{ + writeEntry( pKey.toUtf8().constData(), value, sep, pFlags ); +} + +void KConfigGroup::writeEntry( const char* pKey, + const QVariantList& value, WriteConfigFlags pFlags ) +{ + writeEntry( pKey, QVariant(value), pFlags ); +} + +void KConfigGroup::writeEntry( const char *pKey, const char *value, + WriteConfigFlags pFlags ) +{ + writeEntry(pKey, QString::fromLatin1(value), pFlags); +} + +void KConfigGroup::writeEntry( const char *pKey, const QByteArray& value, + WriteConfigFlags pFlags ) +{ // the KConfig object is dirty now // set this before any IO takes place so that if any derivative // classes do caching, they won't try and flush the cache out @@ -698,7 +723,7 @@ entryKey.bLocal =3D pFlags & KConfigBase::NLS; =20 KEntry aEntryData; =2D aEntryData.mValue =3D value.toUtf8(); // set new value + aEntryData.mValue =3D value; // set new value aEntryData.bGlobal =3D pFlags & KConfigBase::Global; aEntryData.bNLS =3D pFlags & KConfigBase::NLS; =20 @@ -710,31 +735,6 @@ putData(entryKey, aEntryData, true); } =20 =2Dvoid KConfigGroup::writeEntry( const QString& pKey, const QStringList &v= alue, =2D char sep, =2D WriteConfigFlags pFlags ) =2D{ =2D writeEntry( pKey.toUtf8().constData(), value, sep, pFlags ); =2D} =2D =2Dvoid KConfigGroup::writeEntry( const char* pKey, =2D const QVariantList& value, WriteConfigFlags pFlags ) =2D{ =2D writeEntry( pKey, QVariant(value), pFlags ); =2D} =2D =2Dvoid KConfigGroup::writeEntry( const char *pKey, const char *value, =2D WriteConfigFlags pFlags ) =2D{ =2D writeEntry(pKey, QString::fromLatin1(value), pFlags); =2D} =2D =2Dvoid KConfigGroup::writeEntry( const char *pKey, const QByteArray& value, =2D WriteConfigFlags pFlags ) =2D{ =2D writeEntry(pKey, QString::fromLatin1(value, value.size()), pFlags); =2D} =2D void KConfigGroup::writePathEntry( const QString& pKey, const QString & pa= th, KConfigBase::WriteConfigFlags pFlags ) { @@ -888,8 +888,7 @@ writeEntry( pKey, prop.toStringList(), ',', pFlags ); return; case QVariant::ByteArray: { =2D const QByteArray ba =3D prop.toByteArray(); =2D writeEntry( pKey, QString::fromUtf8(ba.constData(), ba.length()), = pFlags ); + writeEntry( pKey, prop.toByteArray(), pFlags ); return; } case QVariant::Point: { --Boundary-00=_Vrd7GuVz+dknYNZ--