Construct a string converter by name

Add a constructor, that allows constructing a string converter by
name. This is required in some cases and also makes it possible to
(in the future) extend the API to 3rd party encodings.

Also add a name() accessor.

Change-Id: I606d6ce9405ee967f76197b803615e27c5b001cf
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
Lars Knoll 2020-04-27 15:08:50 +02:00
parent 2d43f735b4
commit 3ce9162ab5
3 changed files with 87 additions and 9 deletions

View File

@ -1441,15 +1441,46 @@ static qsizetype toLatin1Len(qsizetype l) { return l + 1; }
const QStringConverter::Interface QStringConverter::encodingInterfaces[QStringConverter::LastEncoding + 1] = const QStringConverter::Interface QStringConverter::encodingInterfaces[QStringConverter::LastEncoding + 1] =
{ {
{ QUtf8::convertToUnicode, fromUtf8Len, QUtf8::convertFromUnicode, toUtf8Len }, { "UTF-8", QUtf8::convertToUnicode, fromUtf8Len, QUtf8::convertFromUnicode, toUtf8Len },
{ fromUtf16, fromUtf16Len, toUtf16, toUtf16Len }, { "UTF-16", fromUtf16, fromUtf16Len, toUtf16, toUtf16Len },
{ fromUtf16LE, fromUtf16Len, toUtf16LE, toUtf16Len }, { "UTF-16LE", fromUtf16LE, fromUtf16Len, toUtf16LE, toUtf16Len },
{ fromUtf16BE, fromUtf16Len, toUtf16BE, toUtf16Len }, { "UTF-16BE", fromUtf16BE, fromUtf16Len, toUtf16BE, toUtf16Len },
{ fromUtf32, fromUtf32Len, toUtf32, toUtf32Len }, { "UTF-32", fromUtf32, fromUtf32Len, toUtf32, toUtf32Len },
{ fromUtf32LE, fromUtf32Len, toUtf32LE, toUtf32Len }, { "UTF-32LE", fromUtf32LE, fromUtf32Len, toUtf32LE, toUtf32Len },
{ fromUtf32BE, fromUtf32Len, toUtf32BE, toUtf32Len }, { "UTF-32BE", fromUtf32BE, fromUtf32Len, toUtf32BE, toUtf32Len },
{ fromLatin1, fromLatin1Len, toLatin1, toLatin1Len }, { "ISO-8859-1", fromLatin1, fromLatin1Len, toLatin1, toLatin1Len },
{ fromLocal8Bit, fromUtf8Len, toLocal8Bit, toUtf8Len } { "Locale", fromLocal8Bit, fromUtf8Len, toLocal8Bit, toUtf8Len }
}; };
// match names case insensitive and skipping '-' and '_'
static bool nameMatch(const char *a, const char *b)
{
while (*a && *b) {
if (*a == '-' || *a == '_') {
++a;
continue;
}
if (*b == '-' || *b == '_') {
++b;
continue;
}
if (toupper(*a) != toupper(*b))
return false;
++a;
++b;
}
return !*a && !*b;
}
QStringConverter::QStringConverter(const char *name)
: iface(nullptr)
{
for (int i = 0; i < LastEncoding + 1; ++i) {
if (nameMatch(encodingInterfaces[i].name, name)) {
iface = encodingInterfaces + i;
break;
}
}
}
QT_END_NAMESPACE QT_END_NAMESPACE

View File

@ -132,18 +132,23 @@ protected:
using DecoderFn = QChar * (*)(QChar *out, const char *in, qsizetype length, State *state); using DecoderFn = QChar * (*)(QChar *out, const char *in, qsizetype length, State *state);
using LengthFn = qsizetype (*)(qsizetype inLength); using LengthFn = qsizetype (*)(qsizetype inLength);
using EncoderFn = char * (*)(char *out, QStringView in, State *state); using EncoderFn = char * (*)(char *out, QStringView in, State *state);
const char *name = nullptr;
DecoderFn toUtf16 = nullptr; DecoderFn toUtf16 = nullptr;
LengthFn toUtf16Len = nullptr; LengthFn toUtf16Len = nullptr;
EncoderFn fromUtf16 = nullptr; EncoderFn fromUtf16 = nullptr;
LengthFn fromUtf16Len = nullptr; LengthFn fromUtf16Len = nullptr;
}; };
QSTRINGCONVERTER_CONSTEXPR QStringConverter()
: iface(nullptr)
{}
QSTRINGCONVERTER_CONSTEXPR QStringConverter(Encoding encoding, Flags f) QSTRINGCONVERTER_CONSTEXPR QStringConverter(Encoding encoding, Flags f)
: iface(&encodingInterfaces[int(encoding)]), state(f) : iface(&encodingInterfaces[int(encoding)]), state(f)
{} {}
QSTRINGCONVERTER_CONSTEXPR QStringConverter(const Interface *i) QSTRINGCONVERTER_CONSTEXPR QStringConverter(const Interface *i)
: iface(i) : iface(i)
{} {}
QStringConverter(const char *name);
public: public:
bool isValid() const { return iface != nullptr; } bool isValid() const { return iface != nullptr; }
@ -154,6 +159,9 @@ public:
} }
bool hasError() const { return state.invalidChars != 0; } bool hasError() const { return state.invalidChars != 0; }
const char *name() const
{ return isValid() ? iface->name : nullptr; }
protected: protected:
const Interface *iface; const Interface *iface;
State state; State state;
@ -168,9 +176,15 @@ protected:
: QStringConverter(i) : QStringConverter(i)
{} {}
public: public:
QSTRINGCONVERTER_CONSTEXPR QStringEncoder()
: QStringConverter()
{}
QSTRINGCONVERTER_CONSTEXPR QStringEncoder(Encoding encoding, Flags flags = Flag::Default) QSTRINGCONVERTER_CONSTEXPR QStringEncoder(Encoding encoding, Flags flags = Flag::Default)
: QStringConverter(encoding, flags) : QStringConverter(encoding, flags)
{} {}
QStringEncoder(const char *name)
: QStringConverter(name)
{}
#if defined(QT_USE_FAST_OPERATOR_PLUS) || defined(QT_USE_QSTRINGBUILDER) #if defined(QT_USE_FAST_OPERATOR_PLUS) || defined(QT_USE_QSTRINGBUILDER)
template<typename T> template<typename T>
@ -231,6 +245,12 @@ public:
QSTRINGCONVERTER_CONSTEXPR QStringDecoder(Encoding encoding, Flags flags = Flag::Default) QSTRINGCONVERTER_CONSTEXPR QStringDecoder(Encoding encoding, Flags flags = Flag::Default)
: QStringConverter(encoding, flags) : QStringConverter(encoding, flags)
{} {}
QSTRINGCONVERTER_CONSTEXPR QStringDecoder()
: QStringConverter()
{}
QStringDecoder(const char *name)
: QStringConverter(name)
{}
#if defined(QT_USE_FAST_OPERATOR_PLUS) || defined(QT_USE_QSTRINGBUILDER) #if defined(QT_USE_FAST_OPERATOR_PLUS) || defined(QT_USE_QSTRINGBUILDER)
template<typename T> template<typename T>

View File

@ -39,6 +39,8 @@ class tst_QStringConverter : public QObject
private slots: private slots:
void threadSafety(); void threadSafety();
void constructByName();
void convertUtf8(); void convertUtf8();
void nonFlaggedCodepointFFFF() const; void nonFlaggedCodepointFFFF() const;
@ -59,6 +61,31 @@ private slots:
void utfHeaders(); void utfHeaders();
}; };
void tst_QStringConverter::constructByName()
{
QStringDecoder decoder("UTF-8");
QVERIFY(decoder.isValid());
QVERIFY(!strcmp(decoder.name(), "UTF-8"));
decoder = QStringDecoder("XXX");
QVERIFY(!decoder.isValid());
decoder = QStringDecoder("ISO-8859-1");
QVERIFY(decoder.isValid());
QVERIFY(!strcmp(decoder.name(), "ISO-8859-1"));
decoder = QStringDecoder("UTF-16LE");
QVERIFY(decoder.isValid());
QVERIFY(!strcmp(decoder.name(), "UTF-16LE"));
decoder = QStringDecoder("utf8");
QVERIFY(decoder.isValid());
QVERIFY(!strcmp(decoder.name(), "UTF-8"));
decoder = QStringDecoder("iso8859-1");
QVERIFY(decoder.isValid());
QVERIFY(!strcmp(decoder.name(), "ISO-8859-1"));
decoder = QStringDecoder("utf-16");
QVERIFY(decoder.isValid());
QVERIFY(!strcmp(decoder.name(), "UTF-16"));
}
void tst_QStringConverter::convertUtf8() void tst_QStringConverter::convertUtf8()
{ {
QFile file(QFINDTESTDATA("utf8.txt")); QFile file(QFINDTESTDATA("utf8.txt"));