diff --git a/src/corelib/text/qstringconverter.cpp b/src/corelib/text/qstringconverter.cpp index 7f68c5113e..8857433544 100644 --- a/src/corelib/text/qstringconverter.cpp +++ b/src/corelib/text/qstringconverter.cpp @@ -10,6 +10,7 @@ #include "private/qstringiterator_p.h" #include "private/qtools_p.h" #include "qbytearraymatcher.h" +#include #if QT_CONFIG(icu) #include @@ -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::encodingForName(const char *name) noexcept { @@ -2163,6 +2167,60 @@ std::optional 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 diff --git a/src/corelib/text/qstringconverter_base.h b/src/corelib/text/qstringconverter_base.h index bf464cbb6f..19b6399c05 100644 --- a/src/corelib/text/qstringconverter_base.h +++ b/src/corelib/text/qstringconverter_base.h @@ -13,6 +13,7 @@ #include // QT_{BEGIN,END}_NAMESPACE #include // Q_DECLARE_FLAGS +#include #include @@ -159,6 +160,8 @@ public: encodingForData(QByteArrayView data, char16_t expectedFirstCharacter = 0) noexcept; Q_CORE_EXPORT static std::optional encodingForHtml(QByteArrayView data); + Q_CORE_EXPORT static QStringList availableCodecs(); + protected: const Interface *iface; State state; diff --git a/tests/auto/corelib/text/qstringconverter/tst_qstringconverter.cpp b/tests/auto/corelib/text/qstringconverter/tst_qstringconverter.cpp index 253749ede9..6a969b21b1 100644 --- a/tests/auto/corelib/text/qstringconverter/tst_qstringconverter.cpp +++ b/tests/auto/corelib/text/qstringconverter/tst_qstringconverter.cpp @@ -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: