From e30774649aabdbcaefdcbf21c80bd6484a76580f Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Thu, 3 Apr 2025 11:27:52 -0700 Subject: [PATCH] QLoggingRegistry: replace QTextStream and QFile with MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is to avoid the need to use QFile (which is a QObject) in this early code, especially since QObject itself may use category-logging. Task-number: QTBUG-135326 Change-Id: Idc05974d06c2c0a973f6fffdadcc0ecbf76c5cbc Reviewed-by: Kai Köhne Reviewed-by: Edward Welbourne --- src/corelib/io/qloggingregistry.cpp | 68 ++++++++++++++++++++++++----- src/corelib/io/qloggingregistry_p.h | 2 +- 2 files changed, 58 insertions(+), 12 deletions(-) diff --git a/src/corelib/io/qloggingregistry.cpp b/src/corelib/io/qloggingregistry.cpp index 590a99a9928..8279e1a3a27 100644 --- a/src/corelib/io/qloggingregistry.cpp +++ b/src/corelib/io/qloggingregistry.cpp @@ -6,12 +6,12 @@ #include #include #include +#include #include #include -#include #include #include -#include +#include #if QT_CONFIG(settings) #include @@ -163,12 +163,39 @@ void QLoggingSettingsParser::setContent(QStringView content, char16_t separator) \internal Parses configuration from \a stream. */ -void QLoggingSettingsParser::setContent(QTextStream &stream) +void QLoggingSettingsParser::setContent(FILE *stream) { _rules.clear(); - QString line; - while (stream.readLineInto(&line)) - parseNextLine(qToStringViewIgnoringNull(line)); + + constexpr size_t ChunkSize = 240; + QByteArray buffer(ChunkSize, Qt::Uninitialized); + auto readline = [&](FILE *stream) { + // Read one line into the buffer + + // fgets() always writes the terminating null into the buffer, so we'll + // allow it to write to the QByteArray's null (thus the off by 1). + char *s = fgets(buffer.begin(), buffer.size() + 1, stream); + if (!s) + return QByteArrayView{}; + + qsizetype len = strlen(s); + while (len == buffer.size()) { + // need to grow the buffer + buffer.resizeForOverwrite(buffer.size() + ChunkSize); + s = fgets(buffer.end() - ChunkSize, ChunkSize + 1, stream); + if (!s) + break; + len += strlen(s); + } + QByteArrayView result(buffer.constBegin(), len); + if (result.endsWith('\n')) + result.chop(1); + return result; + }; + + QByteArrayView line; + while (!(line = readline(stream)).isNull()) + parseNextLine(QString::fromUtf8(line)); } /*! @@ -262,19 +289,38 @@ static bool qtLoggingDebug() static QList loadRulesFromFile(const QString &filePath) { + Q_ASSERT(!filePath.isEmpty()); if (qtLoggingDebug()) { debugMsg("Checking \"%s\" for rules", QDir::toNativeSeparators(filePath).toUtf8().constData()); } - QFile file(filePath); - if (file.open(QIODevice::ReadOnly | QIODevice::Text)) { - QTextStream stream(&file); + // We bypass QFile here because QFile is a QObject. + if (Q_UNLIKELY(filePath.at(0) == u':')) { + if (qtLoggingDebug()) { + warnMsg("Attempted to load config rules from Qt resource path \"%ls\"", + qUtf16Printable(filePath)); + } + return {}; + } + +#ifdef Q_OS_WIN + // text mode: let the runtime do CRLF translation + FILE *f = _wfopen(reinterpret_cast(filePath.constBegin()), L"rtN"); +#else + FILE *f = QT_FOPEN(QFile::encodeName(filePath).constBegin(), "re"); +#endif + if (f) { QLoggingSettingsParser parser; - parser.setContent(stream); + parser.setContent(f); + fclose(f); if (qtLoggingDebug()) - debugMsg("Loaded %td rules", static_cast(parser.rules().size())); + debugMsg("Loaded %td rules from \"%ls\"", static_cast(parser.rules().size()), + qUtf16Printable(filePath)); return parser.rules(); + } else if (int err = errno; err != ENOENT) { + warnMsg("Failed to load file \"%ls\": %ls", qUtf16Printable(filePath), + qUtf16Printable(qt_error_string(err))); } return QList(); } diff --git a/src/corelib/io/qloggingregistry_p.h b/src/corelib/io/qloggingregistry_p.h index 582458b27d7..1a6a7787df1 100644 --- a/src/corelib/io/qloggingregistry_p.h +++ b/src/corelib/io/qloggingregistry_p.h @@ -82,7 +82,7 @@ public: void setImplicitRulesSection(bool inRulesSection) { m_inRulesSection = inRulesSection; } void setContent(QStringView content, char16_t separator = u'\n'); - void setContent(QTextStream &stream); + void setContent(FILE *stream); QList rules() const { return _rules; }