Skip to content

Commit

Permalink
Add 'well-formated' JSON string values
Browse files Browse the repository at this point in the history
Add support for surrogate code points U+D800 through U+DFFF,
represent them with JSON escape sequences.

https://github.com/tc39/proposal-well-formed-stringify

Change-Id: I84fea53a8ef400beebefdba10ea82dc510fe7dda
Reviewed-by: Thiago Macieira <[email protected]>
  • Loading branch information
Michal Klocek committed May 14, 2019
1 parent fa59c4f commit 1e5deb0
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 5 deletions.
12 changes: 8 additions & 4 deletions src/corelib/serialization/qjsonwriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@ static inline uchar hexdig(uint u)

static QByteArray escapedString(const QString &s)
{
const uchar replacement = '?';
QByteArray ba(s.length(), Qt::Uninitialized);

uchar *cursor = reinterpret_cast<uchar *>(const_cast<char *>(ba.constData()));
Expand Down Expand Up @@ -111,9 +110,14 @@ static QByteArray escapedString(const QString &s)
} else {
*cursor++ = (uchar)u;
}
} else {
if (QUtf8Functions::toUtf8<QUtf8BaseTraits>(u, cursor, src, end) < 0)
*cursor++ = replacement;
} else if (QUtf8Functions::toUtf8<QUtf8BaseTraits>(u, cursor, src, end) < 0) {
// failed to get valid utf8 use JSON escape sequence
*cursor++ = '\\';
*cursor++ = 'u';
*cursor++ = hexdig(u>>12 & 0x0f);
*cursor++ = hexdig(u>>8 & 0x0f);
*cursor++ = hexdig(u>>4 & 0x0f);
*cursor++ = hexdig(u & 0x0f);
}
}

Expand Down
27 changes: 26 additions & 1 deletion tests/auto/corelib/serialization/json/tst_qtjson.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,8 @@ private Q_SLOTS:
void streamSerializationQJsonValue();
void streamSerializationQJsonValueEmpty();
void streamVariantSerialization();

void escapeSurrogateCodePoints_data();
void escapeSurrogateCodePoints();
private:
QString testDataDir;
};
Expand Down Expand Up @@ -3093,6 +3094,9 @@ void tst_QtJson::streamSerializationQJsonValue_data()
QTest::newRow("string") << QJsonValue{QStringLiteral("bum")};
QTest::newRow("array") << QJsonValue{QJsonArray{12,1,5,6,7}};
QTest::newRow("object") << QJsonValue{QJsonObject{{"foo", 665}, {"bar", 666}}};
// test json escape sequence
QTest::newRow("array with 0xD800") << QJsonValue(QJsonArray{QString(0xD800)});
QTest::newRow("array with 0xDF06,0xD834") << QJsonValue(QJsonArray{QString(0xDF06).append(0xD834)});
}

void tst_QtJson::streamSerializationQJsonValue()
Expand Down Expand Up @@ -3181,5 +3185,26 @@ void tst_QtJson::streamVariantSerialization()
}
}

void tst_QtJson::escapeSurrogateCodePoints_data()
{
QTest::addColumn<QString>("str");
QTest::addColumn<QByteArray>("escStr");
QTest::newRow("0xD800") << QString(0xD800) << QByteArray("\\ud800");
QTest::newRow("0xDF06,0xD834") << QString(0xDF06).append(0xD834) << QByteArray("\\udf06\\ud834");
}

void tst_QtJson::escapeSurrogateCodePoints()
{
QFETCH(QString, str);
QFETCH(QByteArray, escStr);
QJsonArray array;
array.append(str);
QByteArray buffer;
QDataStream save(&buffer, QIODevice::WriteOnly);
save << array;
// verify the buffer has escaped values
QVERIFY(buffer.contains(escStr));
}

QTEST_MAIN(tst_QtJson)
#include "tst_qtjson.moc"

0 comments on commit 1e5deb0

Please sign in to comment.