summaryrefslogtreecommitdiffstats
path: root/src/corelib/text/qlocale.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/text/qlocale.cpp')
-rw-r--r--src/corelib/text/qlocale.cpp123
1 files changed, 60 insertions, 63 deletions
diff --git a/src/corelib/text/qlocale.cpp b/src/corelib/text/qlocale.cpp
index b751ed4579..a630f3a5db 100644
--- a/src/corelib/text/qlocale.cpp
+++ b/src/corelib/text/qlocale.cpp
@@ -491,105 +491,102 @@ int QLocaleData::findLocaleIndex(QLocaleId lid)
return locale_index[fallback];
}
-static bool parse_locale_tag(const QString &input, int &i, QString *result,
- const QString &separators)
-{
- *result = QString(8, Qt::Uninitialized); // worst case according to BCP47
- QChar *pch = result->data();
- const QChar *uc = input.data() + i;
- const int l = input.length();
- int size = 0;
- for (; i < l && size < 8; ++i, ++size) {
- if (separators.contains(*uc))
- break;
- if (! ((uc->unicode() >= 'a' && uc->unicode() <= 'z') ||
- (uc->unicode() >= 'A' && uc->unicode() <= 'Z') ||
- (uc->unicode() >= '0' && uc->unicode() <= '9')) ) // latin only
+static QStringView findTag(QStringView name)
+{
+ const QString separators = QStringLiteral("_-.@");
+ int i = 0;
+ while (i < name.size() && !separators.contains(name[i]))
+ i++;
+ return name.first(i);
+}
+
+static bool validTag(QStringView tag)
+{
+ // Returns false if any character in tag is not an ASCII letter or digit
+ for (const QChar uc : tag) {
+ const char16_t ch = uc.unicode();
+ if (!((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9')))
return false;
- *pch++ = *uc++;
}
- result->truncate(size);
- return true;
+ return tag.size() > 0;
}
-bool qt_splitLocaleName(const QString &name, QString &lang, QString &script, QString &cntry)
+static bool isScript(QStringView tag)
{
- const int length = name.length();
-
- lang = script = cntry = QString();
+ // Every script name is 4 characters, a capital followed by three lower-case;
+ // so a search for tag in allScripts *can* only match if it's aligned.
+ static const QString allScripts =
+ QString::fromLatin1(reinterpret_cast<const char *>(script_code_list),
+ sizeof(script_code_list) - 1);
+ return tag.length() == 4 && allScripts.indexOf(tag) % 4 == 0;
+}
- const QString separators = QStringLiteral("_-.@");
+bool qt_splitLocaleName(QStringView name, QStringView *lang, QStringView *script, QStringView *land)
+{
+ // Assume each of lang, script and land is nullptr or points to an empty QStringView.
enum ParserState { NoState, LangState, ScriptState, CountryState };
ParserState state = LangState;
- for (int i = 0; i < length && state != NoState; ) {
- QString value;
- if (!parse_locale_tag(name, i, &value, separators) ||value.isEmpty())
+ while (name.size() && state != NoState) {
+ const QStringView tag = findTag(name);
+ if (!validTag(tag))
break;
- QChar sep = i < length ? name.at(i) : QChar();
+ name = name.sliced(tag.size());
+ const bool sep = name.size() > 0;
+ if (sep) // tag wasn't all that remained; there was a separator
+ name = name.sliced(1);
+
switch (state) {
case LangState:
- if (!sep.isNull() && !separators.contains(sep)) {
- state = NoState;
- break;
- }
- lang = value;
- if (i == length) {
- // just language was specified
- state = NoState;
- break;
- }
- state = ScriptState;
+ if (tag.size() != 2 && tag.size() != 3)
+ return false;
+ if (lang)
+ *lang = tag;
+ state = sep ? ScriptState : NoState;
break;
- case ScriptState: {
- QString scripts = QString::fromLatin1((const char *)script_code_list,
- sizeof(script_code_list) - 1);
- if (value.length() == 4 && scripts.indexOf(value) % 4 == 0) {
- // script name is always 4 characters
- script = value;
- state = CountryState;
- } else {
- // it wasn't a script, maybe it is a country then?
- cntry = value;
- state = NoState;
+ case ScriptState:
+ if (isScript(tag)) {
+ if (script)
+ *script = tag;
+ state = sep ? CountryState : NoState;
+ break;
}
- break;
- }
+ // It wasn't a script, assume it's a country.
+ Q_FALLTHROUGH();
case CountryState:
- cntry = value;
+ if (land)
+ *land = tag;
state = NoState;
break;
- case NoState:
- // shouldn't happen
- qWarning("QLocale: This should never happen");
+ case NoState: // Precluded by loop condition !
+ Q_ASSERT(!"QLocale: This should never happen");
break;
}
- ++i;
}
- return lang.length() == 2 || lang.length() == 3;
+ return state != LangState;
}
// TODO: kill this ! Still in use by qttools, patch submitted (2020 October).
void QLocalePrivate::getLangAndCountry(const QString &name, QLocale::Language &lang,
- QLocale::Script &script, QLocale::Country &cntry)
+ QLocale::Script &script, QLocale::Country &land)
{
const auto id = QLocaleId::fromName(name);
lang = QLocale::Language(id.language_id);
script = QLocale::Script(id.script_id);
- cntry = QLocale::Country(id.country_id);
+ land = QLocale::Country(id.country_id);
}
QLocaleId QLocaleId::fromName(const QString &name)
{
- QString lang;
- QString script;
- QString cntry;
- if (!qt_splitLocaleName(name, lang, script, cntry))
+ QStringView lang;
+ QStringView script;
+ QStringView land;
+ if (!qt_splitLocaleName(name, &lang, &script, &land))
return { QLocale::C, 0, 0 };
QLocale::Language langId = QLocalePrivate::codeToLanguage(lang);
if (langId == QLocale::C)
return QLocaleId { langId, 0, 0 };
- return { langId, QLocalePrivate::codeToScript(script), QLocalePrivate::codeToCountry(cntry) };
+ return { langId, QLocalePrivate::codeToScript(script), QLocalePrivate::codeToCountry(land) };
}
QString qt_readEscapedFormatString(QStringView format, int *idx)