Provide QStringConverter equivalent of QTextCodec::availableCodecs

A text editor commonly wants to display a list of codecs that are
supported. With the introduction of the ICU based QStringConverter, that
list is no longer statically known. So provide the necessary
functionality.

Fixes: QTBUG-109104
Change-Id: I9ecf59aa6bcc6fe65c8872cab84affafec4fa362
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
This commit is contained in:
Fabian Kosmale 2023-07-17 12:05:44 +03:00
parent bc9ad7db6b
commit 90226018a9
3 changed files with 70 additions and 0 deletions

View File

@ -10,6 +10,7 @@
#include "private/qstringiterator_p.h"
#include "private/qtools_p.h"
#include "qbytearraymatcher.h"
#include <QtCore/qbytearraylist.h>
#if QT_CONFIG(icu)
#include <unicode/ucnv.h>
@ -2032,6 +2033,7 @@ const char *QStringConverter::name() const noexcept
Returns the canonical name of the encoding this QStringConverter can encode or decode.
Returns a nullptr if the converter is not valid.
The returned name is UTF-8 encoded.
\sa isValid()
*/
@ -2043,6 +2045,8 @@ const char *QStringConverter::name() const noexcept
\c{std::nullopt} is returned. Such a name may, none the less, be accepted by
the QStringConverter constructor when Qt is built with ICU, if ICU provides a
converter with the given name.
\a name is expected to be UTF-8 encoded.
*/
std::optional<QStringConverter::Encoding> QStringConverter::encodingForName(const char *name) noexcept
{
@ -2163,6 +2167,60 @@ std::optional<QStringConverter::Encoding> QStringConverter::encodingForHtml(QByt
return Utf8;
}
static qsizetype availableCodecCount()
{
#if !QT_CONFIG(icu)
return QStringConverter::Encoding::LastEncoding;
#else
/* icu contains also the names of what Qt provides
except for the special Locale one (so add one for it)
*/
return 1 + ucnv_countAvailable();
#endif
}
/*!
Returns a list of names of supported codecs. The names returned
by this function can be passed to QStringEncoder's and
QStringDecoder's constructor to create a en- or decoder for
the given codec.
\note The order of codecs is an internal implementation detail
and not guaranteed to be stable.
*/
QStringList QStringConverter::availableCodecs()
{
auto availableCodec = [](qsizetype index) -> QString
{
#if !QT_CONFIG(icu)
return QString::fromLatin1(encodingInterfaces[index].name);
#else
if (index == 0) // "Locale", not provided by icu
return QString::fromLatin1(
encodingInterfaces[QStringConverter::Encoding::System].name);
// this mirrors the setup we do to set a converters name
UErrorCode status = U_ZERO_ERROR;
auto icuName = ucnv_getAvailableName(int32_t(index - 1));
const char *standardName = ucnv_getStandardName(icuName, "MIME", &status);
if (U_FAILURE(status) || !standardName) {
status = U_ZERO_ERROR;
standardName = ucnv_getStandardName(icuName, "IANA", &status);
}
if (!standardName)
standardName = icuName;
return QString::fromLatin1(standardName);
#endif
};
qsizetype codecCount = availableCodecCount();
QStringList result;
result.reserve(codecCount);
for (qsizetype i = 0; i < codecCount; ++i)
result.push_back(availableCodec(i));
return result;
}
/*!
Tries to determine the encoding of the HTML in \a data by looking at leading byte
order marks or a charset specifier in the HTML meta tag and returns a QStringDecoder

View File

@ -13,6 +13,7 @@
#include <QtCore/qglobal.h> // QT_{BEGIN,END}_NAMESPACE
#include <QtCore/qflags.h> // Q_DECLARE_FLAGS
#include <QtCore/qcontainerfwd.h>
#include <cstring>
@ -159,6 +160,8 @@ public:
encodingForData(QByteArrayView data, char16_t expectedFirstCharacter = 0) noexcept;
Q_CORE_EXPORT static std::optional<Encoding> encodingForHtml(QByteArrayView data);
Q_CORE_EXPORT static QStringList availableCodecs();
protected:
const Interface *iface;
State state;

View File

@ -178,6 +178,8 @@ private slots:
void encodingForHtml_data();
void encodingForHtml();
void availableCodesAreAvailable();
};
void tst_QStringConverter::constructByName()
@ -2426,6 +2428,13 @@ void tst_QStringConverter::encodingForHtml()
}
}
void tst_QStringConverter::availableCodesAreAvailable()
{
auto codecs = QStringConverter::availableCodecs();
for (const auto &codecName: codecs)
QVERIFY(QStringEncoder(codecName.toLatin1()).isValid());
}
class LoadAndConvert: public QRunnable
{
public: