Fix MS-Win system locale code to return QString for numeric tokens
QSystemLocale::query() is specified to return a QString (wrapped in a QVariant) for the various tokens used in formatting numbers (zero digit, signs, separators) but the MS-Win back-end was returning QChar (wrapped as QVariant) instead, using the first UCS-2 code-point of the string (even if this was the first of a surrogate pair). The same error shall be perpetrated by its caller, but we can at least DTRT in the back-end, ready for the coming fix (in Qt 6) to its caller. In the process, eliminate some local variables that shadowed a member variable and adapt number-conversion to cope with surrogate-pair digits. Optimised the latter for the case where zero is "0". Change-Id: Idfb416c301add4c961dde613b3dc28b2e31fd0af Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
parent
e05511a364
commit
c0ea88a677
@ -1,6 +1,6 @@
|
|||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
**
|
**
|
||||||
** Copyright (C) 2016 The Qt Company Ltd.
|
** Copyright (C) 2020 The Qt Company Ltd.
|
||||||
** Copyright (C) 2016 Intel Corporation.
|
** Copyright (C) 2016 Intel Corporation.
|
||||||
** Contact: https://www.qt.io/licensing/
|
** Contact: https://www.qt.io/licensing/
|
||||||
**
|
**
|
||||||
@ -106,11 +106,11 @@ struct QSystemLocalePrivate
|
|||||||
{
|
{
|
||||||
QSystemLocalePrivate();
|
QSystemLocalePrivate();
|
||||||
|
|
||||||
QChar zeroDigit();
|
QString zeroDigit();
|
||||||
QChar decimalPoint();
|
QString decimalPoint();
|
||||||
QChar groupSeparator();
|
QString groupSeparator();
|
||||||
QChar negativeSign();
|
QString negativeSign();
|
||||||
QChar positiveSign();
|
QString positiveSign();
|
||||||
QVariant dateFormat(QLocale::FormatType);
|
QVariant dateFormat(QLocale::FormatType);
|
||||||
QVariant timeFormat(QLocale::FormatType);
|
QVariant timeFormat(QLocale::FormatType);
|
||||||
QVariant dateTimeFormat(QLocale::FormatType);
|
QVariant dateTimeFormat(QLocale::FormatType);
|
||||||
@ -147,12 +147,11 @@ private:
|
|||||||
WCHAR lcName[LOCALE_NAME_MAX_LENGTH];
|
WCHAR lcName[LOCALE_NAME_MAX_LENGTH];
|
||||||
#endif
|
#endif
|
||||||
SubstitutionType substitutionType;
|
SubstitutionType substitutionType;
|
||||||
QChar zero;
|
QString zero; // cached value for zeroDigit()
|
||||||
|
|
||||||
int getLocaleInfo(LCTYPE type, LPWSTR data, int size);
|
int getLocaleInfo(LCTYPE type, LPWSTR data, int size);
|
||||||
QString getLocaleInfo(LCTYPE type, int maxlen = 0);
|
QString getLocaleInfo(LCTYPE type, int maxlen = 0);
|
||||||
int getLocaleInfo_int(LCTYPE type, int maxlen = 0);
|
int getLocaleInfo_int(LCTYPE type, int maxlen = 0);
|
||||||
QChar getLocaleInfo_qchar(LCTYPE type);
|
|
||||||
|
|
||||||
int getCurrencyFormat(DWORD flags, LPCWSTR value, const CURRENCYFMTW *format, LPWSTR data, int size);
|
int getCurrencyFormat(DWORD flags, LPCWSTR value, const CURRENCYFMTW *format, LPWSTR data, int size);
|
||||||
int getDateFormat(DWORD flags, const SYSTEMTIME * date, LPCWSTR format, LPWSTR data, int size);
|
int getDateFormat(DWORD flags, const SYSTEMTIME * date, LPCWSTR format, LPWSTR data, int size);
|
||||||
@ -236,12 +235,6 @@ int QSystemLocalePrivate::getLocaleInfo_int(LCTYPE type, int maxlen)
|
|||||||
return ok ? v : 0;
|
return ok ? v : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
QChar QSystemLocalePrivate::getLocaleInfo_qchar(LCTYPE type)
|
|
||||||
{
|
|
||||||
QString str = getLocaleInfo(type);
|
|
||||||
return str.isEmpty() ? QChar() : str.at(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
QSystemLocalePrivate::SubstitutionType QSystemLocalePrivate::substitution()
|
QSystemLocalePrivate::SubstitutionType QSystemLocalePrivate::substitution()
|
||||||
{
|
{
|
||||||
if (substitutionType == SUnknown) {
|
if (substitutionType == SUnknown) {
|
||||||
@ -257,13 +250,12 @@ QSystemLocalePrivate::SubstitutionType QSystemLocalePrivate::substitution()
|
|||||||
else if (buf[0] == '2')
|
else if (buf[0] == '2')
|
||||||
substitutionType = QSystemLocalePrivate::SAlways;
|
substitutionType = QSystemLocalePrivate::SAlways;
|
||||||
else {
|
else {
|
||||||
wchar_t digits[11];
|
wchar_t digits[11]; // See zeroDigit() for why 11.
|
||||||
if (!getLocaleInfo(LOCALE_SNATIVEDIGITS, digits, 11)) {
|
if (!getLocaleInfo(LOCALE_SNATIVEDIGITS, digits, 11)) {
|
||||||
substitutionType = QSystemLocalePrivate::SNever;
|
substitutionType = QSystemLocalePrivate::SNever;
|
||||||
return substitutionType;
|
return substitutionType;
|
||||||
}
|
}
|
||||||
const wchar_t zero = digits[0];
|
if (buf[0] == digits[0] + 2)
|
||||||
if (buf[0] == zero + 2)
|
|
||||||
substitutionType = QSystemLocalePrivate::SAlways;
|
substitutionType = QSystemLocalePrivate::SAlways;
|
||||||
else
|
else
|
||||||
substitutionType = QSystemLocalePrivate::SNever;
|
substitutionType = QSystemLocalePrivate::SNever;
|
||||||
@ -274,40 +266,75 @@ QSystemLocalePrivate::SubstitutionType QSystemLocalePrivate::substitution()
|
|||||||
|
|
||||||
QString &QSystemLocalePrivate::substituteDigits(QString &string)
|
QString &QSystemLocalePrivate::substituteDigits(QString &string)
|
||||||
{
|
{
|
||||||
ushort zero = zeroDigit().unicode();
|
zeroDigit(); // Ensure zero is set.
|
||||||
ushort *qch = reinterpret_cast<ushort *>(string.data());
|
switch (zero.size()) {
|
||||||
for (ushort *end = qch + string.size(); qch != end; ++qch) {
|
case 1: {
|
||||||
if (*qch >= '0' && *qch <= '9')
|
const ushort offset = zero.at(0).unicode() - '0';
|
||||||
*qch = zero + (*qch - '0');
|
if (!offset) // Nothing to do
|
||||||
|
break;
|
||||||
|
Q_ASSERT(offset > 9);
|
||||||
|
ushort *const qch = reinterpret_cast<ushort *>(string.data());
|
||||||
|
for (int i = 0, stop = string.size(); i < stop; ++i) {
|
||||||
|
ushort &ch = qch[i];
|
||||||
|
if (ch >= '0' && ch <= '9')
|
||||||
|
ch += offset;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 2: {
|
||||||
|
// Surrogate pair (high, low):
|
||||||
|
uint digit = QChar::surrogateToUcs4(zero.at(0), zero.at(1));
|
||||||
|
for (int i = 0; i < 10; i++) {
|
||||||
|
const QChar s[2] = { QChar::highSurrogate(digit + i), QChar::lowSurrogate(digit + i) };
|
||||||
|
string.replace(QString(QLatin1Char('0' + i)), QString(s, 2));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
Q_ASSERT(!"Expected zero digit to be a single UCS2 code-point or a surrogate pair");
|
||||||
|
case 0: // Apparently this locale info was not available.
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return string;
|
return string;
|
||||||
}
|
}
|
||||||
|
|
||||||
QChar QSystemLocalePrivate::zeroDigit()
|
QString QSystemLocalePrivate::zeroDigit()
|
||||||
{
|
{
|
||||||
if (zero.isNull())
|
if (zero.isEmpty()) {
|
||||||
zero = getLocaleInfo_qchar(LOCALE_SNATIVEDIGITS);
|
/* Ten digits plus a terminator.
|
||||||
|
|
||||||
|
https://docs.microsoft.com/en-us/windows/win32/intl/locale-snative-constants
|
||||||
|
"Native equivalents of ASCII 0 through 9. The maximum number of
|
||||||
|
characters allowed for this string is eleven, including a terminating
|
||||||
|
null character."
|
||||||
|
*/
|
||||||
|
wchar_t digits[11];
|
||||||
|
if (getLocaleInfo(LOCALE_SNATIVEDIGITS, digits, 11)) {
|
||||||
|
// assert all(digits[i] == i + digits[0] for i in range(1, 10)), assumed above
|
||||||
|
zero = QString::fromWCharArray(digits, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
return zero;
|
return zero;
|
||||||
}
|
}
|
||||||
|
|
||||||
QChar QSystemLocalePrivate::decimalPoint()
|
QString QSystemLocalePrivate::decimalPoint()
|
||||||
{
|
{
|
||||||
return getLocaleInfo_qchar(LOCALE_SDECIMAL);
|
return getLocaleInfo(LOCALE_SDECIMAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
QChar QSystemLocalePrivate::groupSeparator()
|
QString QSystemLocalePrivate::groupSeparator()
|
||||||
{
|
{
|
||||||
return getLocaleInfo_qchar(LOCALE_STHOUSAND);
|
return getLocaleInfo(LOCALE_STHOUSAND);
|
||||||
}
|
}
|
||||||
|
|
||||||
QChar QSystemLocalePrivate::negativeSign()
|
QString QSystemLocalePrivate::negativeSign()
|
||||||
{
|
{
|
||||||
return getLocaleInfo_qchar(LOCALE_SNEGATIVESIGN);
|
return getLocaleInfo(LOCALE_SNEGATIVESIGN);
|
||||||
}
|
}
|
||||||
|
|
||||||
QChar QSystemLocalePrivate::positiveSign()
|
QString QSystemLocalePrivate::positiveSign()
|
||||||
{
|
{
|
||||||
return getLocaleInfo_qchar(LOCALE_SPOSITIVESIGN);
|
return getLocaleInfo(LOCALE_SPOSITIVESIGN);
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant QSystemLocalePrivate::dateFormat(QLocale::FormatType type)
|
QVariant QSystemLocalePrivate::dateFormat(QLocale::FormatType type)
|
||||||
@ -677,7 +704,7 @@ void QSystemLocalePrivate::update()
|
|||||||
GetUserDefaultLocaleName(lcName, LOCALE_NAME_MAX_LENGTH);
|
GetUserDefaultLocaleName(lcName, LOCALE_NAME_MAX_LENGTH);
|
||||||
#endif
|
#endif
|
||||||
substitutionType = SUnknown;
|
substitutionType = SUnknown;
|
||||||
zero = QChar();
|
zero.resize(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString QSystemLocalePrivate::winToQtFormat(QStringView sys_fmt)
|
QString QSystemLocalePrivate::winToQtFormat(QStringView sys_fmt)
|
||||||
@ -749,7 +776,7 @@ QLocale QSystemLocale::fallbackUiLocale() const
|
|||||||
return QLocale(QString::fromLatin1(getWinLocaleName()));
|
return QLocale(QString::fromLatin1(getWinLocaleName()));
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant QSystemLocale::query(QueryType type, QVariant in = QVariant()) const
|
QVariant QSystemLocale::query(QueryType type, QVariant in) const
|
||||||
{
|
{
|
||||||
QSystemLocalePrivate *d = systemLocalePrivate();
|
QSystemLocalePrivate *d = systemLocalePrivate();
|
||||||
switch(type) {
|
switch(type) {
|
||||||
|
Loading…
Reference in New Issue
Block a user