QString: preserve embedded NULs when converting from QByteArray

Unearthed an off-by-one error in a QByteArray::fromRawData() call in
tst_qtextdocumentfragment. Fixed by porting to QStringLiteral.

[ChangeLog][Important Behavior Changes] All conversions from QByteArray
to QString now preserve embedded NULs. This is done in order to provide a
faster conversion from QByteArray to QString that does not involve a call to
strlen. If you need the old behavior, convert from QByteArray::constData()
instead. If you are porting from Qt 4, we suggest to make your source compile
with QT_NO_CAST_FROM_BYTEARRAY before porting to Qt 5.

Change-Id: Ibca40f503920fee6f3a5f0d74a04b38b8849796f
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
Marc Mutz 2015-02-17 15:02:05 +01:00
parent 6f145707eb
commit e486d69133
3 changed files with 23 additions and 58 deletions

View File

@ -84,7 +84,7 @@ class QLatin1String
public:
Q_DECL_CONSTEXPR inline explicit QLatin1String(const char *s) : m_size(s ? int(strlen(s)) : 0), m_data(s) {}
Q_DECL_CONSTEXPR inline explicit QLatin1String(const char *s, int sz) : m_size(sz), m_data(s) {}
inline explicit QLatin1String(const QByteArray &s) : m_size(int(qstrnlen(s.constData(), s.size()))), m_data(s.constData()) {}
inline explicit QLatin1String(const QByteArray &s) : m_size(s.size()), m_data(s.constData()) {}
inline const char *latin1() const { return m_data; }
inline int size() const { return m_size; }
@ -534,11 +534,11 @@ public:
return fromLocal8Bit_helper(str, (str && size == -1) ? int(strlen(str)) : size);
}
static inline QString fromLatin1(const QByteArray &str)
{ return str.isNull() ? QString() : fromLatin1(str.data(), qstrnlen(str.constData(), str.size())); }
{ return str.isNull() ? QString() : fromLatin1(str.data(), str.size()); }
static inline QString fromUtf8(const QByteArray &str)
{ return str.isNull() ? QString() : fromUtf8(str.data(), qstrnlen(str.constData(), str.size())); }
{ return str.isNull() ? QString() : fromUtf8(str.data(), str.size()); }
static inline QString fromLocal8Bit(const QByteArray &str)
{ return str.isNull() ? QString() : fromLocal8Bit(str.data(), qstrnlen(str.constData(), str.size())); }
{ return str.isNull() ? QString() : fromLocal8Bit(str.data(), str.size()); }
static QString fromUtf16(const ushort *, int size = -1);
static QString fromUcs4(const uint *, int size = -1);
static QString fromRawData(const QChar *, int size);
@ -650,7 +650,7 @@ public:
: d(fromAscii_helper(ch, ch ? int(strlen(ch)) : -1))
{}
inline QT_ASCII_CAST_WARN QString(const QByteArray &a)
: d(fromAscii_helper(a.constData(), qstrnlen(a.constData(), a.size())))
: d(fromAscii_helper(a.constData(), a.size()))
{}
inline QT_ASCII_CAST_WARN QString &operator=(const char *ch)
{ return (*this = fromUtf8(ch)); }
@ -1211,30 +1211,30 @@ inline QT_ASCII_CAST_WARN bool QLatin1String::operator>=(const QByteArray &s) co
{ return QString::fromUtf8(s) <= *this; }
inline QT_ASCII_CAST_WARN bool QString::operator==(const QByteArray &s) const
{ return QString::compare_helper(constData(), size(), s.constData(), qstrnlen(s.constData(), s.size())) == 0; }
{ return QString::compare_helper(constData(), size(), s.constData(), s.size()) == 0; }
inline QT_ASCII_CAST_WARN bool QString::operator!=(const QByteArray &s) const
{ return QString::compare_helper(constData(), size(), s.constData(), qstrnlen(s.constData(), s.size())) != 0; }
{ return QString::compare_helper(constData(), size(), s.constData(), s.size()) != 0; }
inline QT_ASCII_CAST_WARN bool QString::operator<(const QByteArray &s) const
{ return QString::compare_helper(constData(), size(), s.constData(), qstrnlen(s.constData(), s.size())) < 0; }
{ return QString::compare_helper(constData(), size(), s.constData(), s.size()) < 0; }
inline QT_ASCII_CAST_WARN bool QString::operator>(const QByteArray &s) const
{ return QString::compare_helper(constData(), size(), s.constData(), qstrnlen(s.constData(), s.size())) > 0; }
{ return QString::compare_helper(constData(), size(), s.constData(), s.size()) > 0; }
inline QT_ASCII_CAST_WARN bool QString::operator<=(const QByteArray &s) const
{ return QString::compare_helper(constData(), size(), s.constData(), qstrnlen(s.constData(), s.size())) <= 0; }
{ return QString::compare_helper(constData(), size(), s.constData(), s.size()) <= 0; }
inline QT_ASCII_CAST_WARN bool QString::operator>=(const QByteArray &s) const
{ return QString::compare_helper(constData(), size(), s.constData(), qstrnlen(s.constData(), s.size())) >= 0; }
{ return QString::compare_helper(constData(), size(), s.constData(), s.size()) >= 0; }
inline bool QByteArray::operator==(const QString &s) const
{ return QString::compare_helper(s.constData(), s.size(), constData(), qstrnlen(constData(), size())) == 0; }
{ return QString::compare_helper(s.constData(), s.size(), constData(), size()) == 0; }
inline bool QByteArray::operator!=(const QString &s) const
{ return QString::compare_helper(s.constData(), s.size(), constData(), qstrnlen(constData(), size())) != 0; }
{ return QString::compare_helper(s.constData(), s.size(), constData(), size()) != 0; }
inline bool QByteArray::operator<(const QString &s) const
{ return QString::compare_helper(s.constData(), s.size(), constData(), qstrnlen(constData(), size())) < 0; }
{ return QString::compare_helper(s.constData(), s.size(), constData(), size()) < 0; }
inline bool QByteArray::operator>(const QString &s) const
{ return QString::compare_helper(s.constData(), s.size(), constData(), qstrnlen(constData(), size())) > 0; }
{ return QString::compare_helper(s.constData(), s.size(), constData(), size()) > 0; }
inline bool QByteArray::operator<=(const QString &s) const
{ return QString::compare_helper(s.constData(), s.size(), constData(), qstrnlen(constData(), size())) <= 0; }
{ return QString::compare_helper(s.constData(), s.size(), constData(), size()) <= 0; }
inline bool QByteArray::operator>=(const QString &s) const
{ return QString::compare_helper(s.constData(), s.size(), constData(), qstrnlen(constData(), size())) >= 0; }
{ return QString::compare_helper(s.constData(), s.size(), constData(), size()) >= 0; }
#endif // !defined(QT_NO_CAST_FROM_ASCII) && !defined(QT_RESTRICTED_CAST_FROM_ASCII)
#ifndef QT_NO_CAST_TO_ASCII

View File

@ -828,7 +828,7 @@ void tst_QString::constructorQByteArray_data()
ba1[5] = 'e';
ba1[6] = 'f';
QTest::newRow( "2" ) << ba1 << QString("abc");
QTest::newRow( "2" ) << ba1 << QStringLiteral("abc\0def");
QTest::newRow( "3" ) << QByteArray::fromRawData("abcd", 3) << QString("abc");
QTest::newRow( "4" ) << QByteArray("\xc3\xa9") << QString("\xc3\xa9");
@ -849,12 +849,6 @@ void tst_QString::constructorQByteArray()
QCOMPARE( strBA, expected );
// test operator= too
if (src.constData()[src.length()] == '\0') {
str1.clear();
str1 = src.constData();
QCOMPARE( str1, expected );
}
strBA.clear();
strBA = src;
QCOMPARE( strBA, expected );
@ -2177,14 +2171,6 @@ void tst_QString::append_bytearray()
QTEST( str, "res" );
}
QFETCH( QByteArray, ba );
if (ba.constData()[ba.length()] == '\0') {
QFETCH( QString, str );
str.append(ba.constData());
QTEST( str, "res" );
}
}
void tst_QString::operator_pluseq_bytearray_data()
@ -2210,14 +2196,6 @@ void tst_QString::operator_pluseq_bytearray()
QTEST( str, "res" );
}
QFETCH( QByteArray, ba );
if (ba.constData()[ba.length()] == '\0') {
QFETCH( QString, str );
str += ba.constData();
QTEST( str, "res" );
}
}
void tst_QString::operator_eqeq_bytearray_data()
@ -2232,11 +2210,6 @@ void tst_QString::operator_eqeq_bytearray()
QVERIFY(expected == src);
QVERIFY(!(expected != src));
if (src.constData()[src.length()] == '\0') {
QVERIFY(expected == src.constData());
QVERIFY(!(expected != src.constData()));
}
}
void tst_QString::swap()
@ -2271,7 +2244,7 @@ void tst_QString::prepend_bytearray_data()
// byte array with only a 0
ba.resize( 1 );
ba[0] = 0;
QTest::newRow( "emptyString" ) << QString("foobar ") << ba << QString("foobar ");
QTest::newRow( "emptyString" ) << QString("foobar ") << ba << QStringLiteral("\0foobar ");
// empty byte array
ba.resize( 0 );
@ -2301,14 +2274,6 @@ void tst_QString::prepend_bytearray()
QTEST( str, "res" );
}
QFETCH( QByteArray, ba );
if (ba.constData()[ba.length()] == '\0') {
QFETCH( QString, str );
str.prepend(ba.constData());
QTEST( str, "res" );
}
}
void tst_QString::replace_uint_uint()

View File

@ -1378,8 +1378,8 @@ void tst_QTextDocumentFragment::html_listStart1()
{
// don't create a block for the <ul> element, even if there's some whitespace between
// it and the <li>
const char html[] = "<ul> <li>list item</li><ul>";
cursor.insertFragment(QTextDocumentFragment::fromHtml(QByteArray::fromRawData(html, sizeof(html) / sizeof(html[0]))));
const QString html = QStringLiteral("<ul> <li>list item</li><ul>");
cursor.insertFragment(QTextDocumentFragment::fromHtml(html));
QCOMPARE(doc->blockCount(), 1);
}
@ -1387,8 +1387,8 @@ void tst_QTextDocumentFragment::html_listStart1()
void tst_QTextDocumentFragment::html_listStart2()
{
// unlike with html_listStart1 we want a block showing the 'buggy' text here
const char html[] = "<ul>buggy, but text should appear<li>list item</li><ul>";
cursor.insertFragment(QTextDocumentFragment::fromHtml(QByteArray::fromRawData(html, sizeof(html) / sizeof(html[0]))));
const QString html = QStringLiteral("<ul>buggy, but text should appear<li>list item</li><ul>");
cursor.insertFragment(QTextDocumentFragment::fromHtml(html));
QCOMPARE(doc->blockCount(), 2);
}