summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/corelib/io/qdebug.cpp103
-rw-r--r--src/corelib/io/qdebug.h5
-rw-r--r--src/corelib/io/qtextstream.cpp4
-rw-r--r--src/corelib/io/qtextstream.h1
-rw-r--r--src/testlib/qtestcase.cpp2
-rw-r--r--tests/auto/corelib/io/qdebug/tst_qdebug.cpp67
-rw-r--r--tests/auto/testlib/selftests/expected_badxml.lightxml2
-rw-r--r--tests/auto/testlib/selftests/expected_badxml.xml2
-rw-r--r--tests/auto/testlib/selftests/expected_badxml.xunitxml4
9 files changed, 182 insertions, 8 deletions
diff --git a/src/corelib/io/qdebug.cpp b/src/corelib/io/qdebug.cpp
index 050a48bd65..d8b77dd603 100644
--- a/src/corelib/io/qdebug.cpp
+++ b/src/corelib/io/qdebug.cpp
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2014 Intel Corporation.
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtCore module of the Qt Toolkit.
@@ -40,9 +41,12 @@
#include "qdebug.h"
#include <private/qtextstream_p.h>
+#include <private/qtools_p.h>
QT_BEGIN_NAMESPACE
+using QtMiscUtils::toHexUpper;
+
// This file is needed to force compilation of QDebug into the kernel library.
/*!
@@ -168,6 +172,105 @@ void QDebug::putUcs4(uint ucs4)
maybeQuote('\'');
}
+template <typename Char>
+static inline void putEscapedString(QTextStreamPrivate *d, const Char *begin, int length)
+{
+ QChar quote(QLatin1Char('"'));
+ d->write(&quote, 1);
+
+ const Char *end = begin + length;
+ for (const Char *p = begin; p != end; ++p) {
+ if (sizeof(Char) == sizeof(QChar)) {
+ int runLength = 0;
+ while (p + runLength != end &&
+ p[runLength] < 0x7f && p[runLength] >= 0x20 && p[runLength] != '\\' && p[runLength] != '"')
+ ++runLength;
+ if (runLength) {
+ d->write(reinterpret_cast<const QChar *>(p), runLength);
+ p += runLength - 1;
+ continue;
+ }
+ }
+
+ // print as an escape sequence
+ int buflen = 2;
+ ushort buf[sizeof "\\U12345678" - 1];
+ buf[0] = '\\';
+
+ switch (*p) {
+ case '"':
+ case '\\':
+ buf[1] = *p;
+ break;
+ case '\b':
+ buf[1] = 'b';
+ break;
+ case '\f':
+ buf[1] = 'f';
+ break;
+ case '\n':
+ buf[1] = 'n';
+ break;
+ case '\r':
+ buf[1] = 'r';
+ break;
+ case '\t':
+ buf[1] = 't';
+ break;
+ default:
+ if (QChar::isHighSurrogate(*p)) {
+ if ((p + 1) != end && QChar::isLowSurrogate(p[1])) {
+ // properly-paired surrogates
+ uint ucs4 = QChar::surrogateToUcs4(*p, p[1]);
+ ++p;
+ buf[1] = 'U';
+ buf[2] = '0'; // toHexUpper(ucs4 >> 32);
+ buf[3] = '0'; // toHexUpper(ucs4 >> 28);
+ buf[4] = toHexUpper(ucs4 >> 20);
+ buf[5] = toHexUpper(ucs4 >> 16);
+ buf[6] = toHexUpper(ucs4 >> 12);
+ buf[7] = toHexUpper(ucs4 >> 8);
+ buf[8] = toHexUpper(ucs4 >> 4);
+ buf[9] = toHexUpper(ucs4);
+ buflen = 10;
+ break;
+ }
+ // improperly-paired surrogates, fall through
+ }
+ buf[1] = 'u';
+ if (sizeof(Char) == 1) {
+ buf[2] = buf[3] = '0';
+ } else {
+ buf[2] = toHexUpper(*p >> 12);
+ buf[3] = toHexUpper(*p >> 8);
+ }
+ buf[4] = toHexUpper(*p >> 4);
+ buf[5] = toHexUpper(*p);
+ buflen = 6;
+ }
+ d->write(reinterpret_cast<QChar *>(buf), buflen);
+ }
+
+ d->write(&quote, 1);
+}
+
+/*!
+ \internal
+ Duplicated from QtTest::toPrettyUnicode().
+*/
+void QDebug::putString(const QChar *begin, size_t length)
+{
+ if (stream->testFlag(Stream::NoQuotes)) {
+ // no quotes, write the string directly too (no pretty-printing)
+ // this respects the QTextStream state, though
+ stream->ts.d_ptr->putString(begin, length);
+ } else {
+ // we'll reset the QTextStream formatting mechanisms, so save the state
+ QDebugStateSaver saver(*this);
+ stream->ts.d_ptr->params.reset();
+ putEscapedString(stream->ts.d_ptr.data(), reinterpret_cast<const ushort *>(begin), length);
+ }
+}
/*!
\fn QDebug::swap(QDebug &other)
diff --git a/src/corelib/io/qdebug.h b/src/corelib/io/qdebug.h
index 99c2909aa0..a2d6598bce 100644
--- a/src/corelib/io/qdebug.h
+++ b/src/corelib/io/qdebug.h
@@ -78,6 +78,7 @@ class Q_CORE_EXPORT QDebug
} *stream;
void putUcs4(uint ucs4);
+ void putString(const QChar *begin, size_t length);
public:
inline QDebug(QIODevice *device) : stream(new Stream(device)) {}
inline QDebug(QString *string) : stream(new Stream(string)) {}
@@ -118,8 +119,8 @@ public:
inline QDebug &operator<<(float t) { stream->ts << t; return maybeSpace(); }
inline QDebug &operator<<(double t) { stream->ts << t; return maybeSpace(); }
inline QDebug &operator<<(const char* t) { stream->ts << QString::fromUtf8(t); return maybeSpace(); }
- inline QDebug &operator<<(const QString & t) { maybeQuote(); stream->ts << t; maybeQuote(); return maybeSpace(); }
- inline QDebug &operator<<(const QStringRef & t) { return operator<<(t.toString()); }
+ inline QDebug &operator<<(const QString & t) { putString(t.constData(), uint(t.length())); return maybeSpace(); }
+ inline QDebug &operator<<(const QStringRef & t) { putString(t.constData(), uint(t.length())); return maybeSpace(); }
inline QDebug &operator<<(QLatin1String t) { maybeQuote(); stream->ts << t; maybeQuote(); return maybeSpace(); }
inline QDebug &operator<<(const QByteArray & t) { maybeQuote(); stream->ts << t; maybeQuote(); return maybeSpace(); }
inline QDebug &operator<<(const void * t) { stream->ts << t; return maybeSpace(); }
diff --git a/src/corelib/io/qtextstream.cpp b/src/corelib/io/qtextstream.cpp
index 5f3177e58f..771067fa14 100644
--- a/src/corelib/io/qtextstream.cpp
+++ b/src/corelib/io/qtextstream.cpp
@@ -806,7 +806,7 @@ inline void QTextStreamPrivate::restoreToSavedConverterState()
/*!
\internal
*/
-inline void QTextStreamPrivate::write(const QChar *data, int len)
+void QTextStreamPrivate::write(const QChar *data, int len)
{
if (string) {
// ### What about seek()??
@@ -885,7 +885,7 @@ inline void QTextStreamPrivate::putChar(QChar ch)
/*!
\internal
*/
-inline void QTextStreamPrivate::putString(const QChar *data, int len, bool number)
+void QTextStreamPrivate::putString(const QChar *data, int len, bool number)
{
QString pad;
int padLeft = 0, padRight = 0;
diff --git a/src/corelib/io/qtextstream.h b/src/corelib/io/qtextstream.h
index 5c75a006af..b15e7772e2 100644
--- a/src/corelib/io/qtextstream.h
+++ b/src/corelib/io/qtextstream.h
@@ -185,6 +185,7 @@ public:
private:
Q_DISABLE_COPY(QTextStream)
friend class QDebugStateSaverPrivate;
+ friend class QDebug;
QScopedPointer<QTextStreamPrivate> d_ptr;
};
diff --git a/src/testlib/qtestcase.cpp b/src/testlib/qtestcase.cpp
index a2e4b66ebf..4e7ab18e9b 100644
--- a/src/testlib/qtestcase.cpp
+++ b/src/testlib/qtestcase.cpp
@@ -2146,6 +2146,8 @@ char *toHexRepresentation(const char *ba, int length)
\internal
Returns the same QString but with only the ASCII characters still shown;
everything else is replaced with \c {\uXXXX}.
+
+ Similar to QDebug::putString().
*/
char *toPrettyUnicode(const ushort *p, int length)
{
diff --git a/tests/auto/corelib/io/qdebug/tst_qdebug.cpp b/tests/auto/corelib/io/qdebug/tst_qdebug.cpp
index 015a13775d..63de953437 100644
--- a/tests/auto/corelib/io/qdebug/tst_qdebug.cpp
+++ b/tests/auto/corelib/io/qdebug/tst_qdebug.cpp
@@ -52,6 +52,7 @@ private slots:
void stateSaver() const;
void veryLongWarningMessage() const;
void qDebugQChar() const;
+ void qDebugQString() const;
void qDebugQStringRef() const;
void qDebugQLatin1String() const;
void qDebugQByteArray() const;
@@ -344,6 +345,54 @@ void tst_QDebug::qDebugQChar() const
}
+void tst_QDebug::qDebugQString() const
+{
+ /* Use a basic string. */
+ {
+ QString file, function;
+ int line = 0;
+ const QString in(QLatin1String("input"));
+ const QStringRef inRef(&in);
+
+ MessageHandlerSetter mhs(myMessageHandler);
+ { qDebug() << inRef; }
+#ifndef QT_NO_MESSAGELOGCONTEXT
+ file = __FILE__; line = __LINE__ - 2; function = Q_FUNC_INFO;
+#endif
+ QCOMPARE(s_msgType, QtDebugMsg);
+ QCOMPARE(s_msg, QString::fromLatin1("\"input\""));
+ QCOMPARE(QString::fromLatin1(s_file), file);
+ QCOMPARE(s_line, line);
+ QCOMPARE(QString::fromLatin1(s_function), function);
+ }
+
+ /* simpler tests from now on */
+ MessageHandlerSetter mhs(myMessageHandler);
+
+ QString string = "Hello";
+ qDebug() << string;
+ QCOMPARE(s_msg, QString("\"Hello\""));
+
+ qDebug().noquote().nospace() << string;
+ QCOMPARE(s_msg, string);
+
+ qDebug().noquote().nospace() << qSetFieldWidth(8) << string;
+ QCOMPARE(s_msg, " " + string);
+
+ string = QLatin1String("\nSm\xF8rg\xE5sbord\\");
+ qDebug().noquote().nospace() << string;
+ QCOMPARE(s_msg, string);
+
+ qDebug() << string;
+ QCOMPARE(s_msg, QString("\"\\nSm\\u00F8rg\\u00E5sbord\\\\\""));
+
+ // surrogate pairs (including broken pairings)
+ ushort utf16[] = { 0xDC00, 0xD800, 0xDC00, 'x', 0xD800, 0xDC00, 0xD800, 0 };
+ string = QString::fromUtf16(utf16);
+ qDebug() << string;
+ QCOMPARE(s_msg, QString("\"\\uDC00\\U00010000x\\U00010000\\uD800\""));
+}
+
void tst_QDebug::qDebugQStringRef() const
{
/* Use a basic string. */
@@ -403,6 +452,24 @@ void tst_QDebug::qDebugQLatin1String() const
QCOMPARE(QString::fromLatin1(s_file), file);
QCOMPARE(s_line, line);
QCOMPARE(QString::fromLatin1(s_function), function);
+
+ /* simpler tests from now on */
+ QLatin1String string("\"Hello\"");
+ qDebug() << string;
+ QCOMPARE(s_msg, QString("\"\\\"Hello\\\"\""));
+
+ qDebug().noquote().nospace() << string;
+ QCOMPARE(s_msg, QString(string));
+
+ qDebug().noquote().nospace() << qSetFieldWidth(8) << string;
+ QCOMPARE(s_msg, " " + QString(string));
+
+ string = QLatin1String("\nSm\xF8rg\xE5sbord\\");
+ qDebug().noquote().nospace() << string;
+ QCOMPARE(s_msg, QString(string));
+
+ qDebug() << string;
+ QCOMPARE(s_msg, QString("\"\\nSm\\u00F8rg\\u00E5sbord\\\\\""));
}
void tst_QDebug::qDebugQByteArray() const
diff --git a/tests/auto/testlib/selftests/expected_badxml.lightxml b/tests/auto/testlib/selftests/expected_badxml.lightxml
index 94f479a79a..e0de44f0be 100644
--- a/tests/auto/testlib/selftests/expected_badxml.lightxml
+++ b/tests/auto/testlib/selftests/expected_badxml.lightxml
@@ -113,7 +113,7 @@
</TestFunction>
<TestFunction name="encoding">
<Message type="qdebug" file="" line="0">
- <Description><![CDATA["Ülrich Ümläut"]]></Description>
+ <Description><![CDATA["\u00DClrich \u00DCml\u00E4ut"]]></Description>
</Message>
<Incident type="pass" file="" line="0" />
<Duration msecs="0"/>
diff --git a/tests/auto/testlib/selftests/expected_badxml.xml b/tests/auto/testlib/selftests/expected_badxml.xml
index c1266bfeed..8667c2d9cd 100644
--- a/tests/auto/testlib/selftests/expected_badxml.xml
+++ b/tests/auto/testlib/selftests/expected_badxml.xml
@@ -115,7 +115,7 @@
</TestFunction>
<TestFunction name="encoding">
<Message type="qdebug" file="" line="0">
- <Description><![CDATA["Ülrich Ümläut"]]></Description>
+ <Description><![CDATA["\u00DClrich \u00DCml\u00E4ut"]]></Description>
</Message>
<Incident type="pass" file="" line="0" />
<Duration msecs="0"/>
diff --git a/tests/auto/testlib/selftests/expected_badxml.xunitxml b/tests/auto/testlib/selftests/expected_badxml.xunitxml
index 49048fdad6..46f4be4391 100644
--- a/tests/auto/testlib/selftests/expected_badxml.xunitxml
+++ b/tests/auto/testlib/selftests/expected_badxml.xunitxml
@@ -30,7 +30,7 @@
<failure message="failure message" result="fail"/>
</testcase>
<testcase result="pass" name="encoding">
- <!-- message="&quot;Ülrich Ümläut&quot;" type="qdebug" -->
+ <!-- message="&quot;\u00DClrich \u00DCml\u00E4ut&quot;" type="qdebug" -->
</testcase>
<testcase result="pass" name="cleanupTestCase"/>
<system-err>
@@ -46,6 +46,6 @@
<![CDATA[quotes " text" more text]]>
<![CDATA[xml close > open < tags < text]]>
<![CDATA[all > " mixed ]]]><![CDATA[]> up > " in < the ]]]><![CDATA[]> hopes < of triggering "< ]]]><![CDATA[]> bugs]]>
-<![CDATA["Ülrich Ümläut"]]>
+<![CDATA["\u00DClrich \u00DCml\u00E4ut"]]>
</system-err>
</testsuite>