From fa5a3ef6be2faed2f77d3eea4cf6c0f9e8f176ce Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 17 Oct 2026 23:25:27 +0000 Subject: [PATCH] Don't treat ASCII information separators as binary data isTextOnly() treats every control character which Qt does not consider white space as a sign of binary data, so text containing the ASCII information separators CHAR(28) to CHAR(31) was displayed as a BLOB. These characters are regularly used as field and record delimiters in text, so exempt U+001C to U+001F from the check. The new test rows fail without this change. Fixes #4193 --- src/Data.cpp | 5 ++++- src/tests/TestRegex.cpp | 22 ++++++++++++++++++++++ src/tests/TestRegex.h | 2 ++ 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/src/Data.cpp b/src/Data.cpp index 9be484347..0ebf9a4a5 100644 --- a/src/Data.cpp +++ b/src/Data.cpp @@ -51,7 +51,10 @@ bool isTextOnly(QByteArray data, const QString& encoding, bool quickTest) QString text (data); bool isPrintable = true; for(QChar character : text) { - if(character.isNonCharacter() || (character.category() == QChar::Other_Control && !character.isSpace())) { + // The ASCII information separators (U+001C to U+001F) are control characters which Qt does not consider + // white space. They are regularly used as field delimiters in text, though, so don't treat them as binary. + const bool isSeparator = character.unicode() >= 0x1C && character.unicode() <= 0x1F; + if(character.isNonCharacter() || (character.category() == QChar::Other_Control && !character.isSpace() && !isSeparator)) { isPrintable = false; break; } diff --git a/src/tests/TestRegex.cpp b/src/tests/TestRegex.cpp index b05d7a966..d725df5f3 100644 --- a/src/tests/TestRegex.cpp +++ b/src/tests/TestRegex.cpp @@ -42,6 +42,28 @@ void TestRegex::clipboardRows() QVERIFY(parseClipboard(text) == expected); } +void TestRegex::isTextOnlyControlCharacters_data() +{ + QTest::addColumn("data"); + QTest::addColumn("expected"); + + QTest::newRow("plain") << QByteArray("John Mary") << true; + QTest::newRow("whitespace-controls") << QByteArray("a\tb\r\nc") << true; + QTest::newRow("unit-separator") << QByteArray("John\x1f" "Mary") << true; + QTest::newRow("record-separator") << QByteArray("a\x1e" "b") << true; + QTest::newRow("group-and-file-separator") << QByteArray("a\x1d" "b\x1c" "c") << true; + QTest::newRow("nul") << QByteArray("a\0b", 3) << false; + QTest::newRow("bell") << QByteArray("a\x07" "b") << false; + QTest::newRow("escape") << QByteArray("a\x1b" "b") << false; +} + +void TestRegex::isTextOnlyControlCharacters() +{ + QFETCH(QByteArray, data); + QFETCH(bool, expected); + QCOMPARE(isTextOnly(data), expected); +} + void TestRegex::sqlQueryComments_data() { QTest::addColumn("dirtyQuery"); diff --git a/src/tests/TestRegex.h b/src/tests/TestRegex.h index d96e71326..f2c908502 100644 --- a/src/tests/TestRegex.h +++ b/src/tests/TestRegex.h @@ -14,6 +14,8 @@ private slots: void sqlQueryComments_data(); void clipboardRows(); void clipboardRows_data(); + void isTextOnlyControlCharacters(); + void isTextOnlyControlCharacters_data(); }; #endif