diff options
Diffstat (limited to 'src/corelib/time/qtimezoneprivate.cpp')
-rw-r--r-- | src/corelib/time/qtimezoneprivate.cpp | 48 |
1 files changed, 44 insertions, 4 deletions
diff --git a/src/corelib/time/qtimezoneprivate.cpp b/src/corelib/time/qtimezoneprivate.cpp index cb019fa1a5..facdf6661d 100644 --- a/src/corelib/time/qtimezoneprivate.cpp +++ b/src/corelib/time/qtimezoneprivate.cpp @@ -1,5 +1,6 @@ /**************************************************************************** ** +** Copyright (C) 2019 The Qt Company Ltd. ** Copyright (C) 2013 John Layt <jlayt@kde.org> ** Contact: https://www.qt.io/licensing/ ** @@ -764,6 +765,39 @@ QUtcTimeZonePrivate::QUtcTimeZonePrivate(const QByteArray &id) } } +qint64 QUtcTimeZonePrivate::offsetFromUtcString(const QByteArray &id) +{ + // Convert reasonable UTC[+-]\d+(:\d+){,2} to offset in seconds. + // Assumption: id has already been tried as a CLDR UTC offset ID (notably + // including plain "UTC" itself) and a system offset ID; it's neither. + if (!id.startsWith("UTC") || id.size() < 5) + return invalidSeconds(); // Doesn't match + const char signChar = id.at(3); + if (signChar != '-' && signChar != '+') + return invalidSeconds(); // No sign + const int sign = signChar == '-' ? -1 : 1; + + const auto offsets = id.mid(4).split(':'); + if (offsets.isEmpty() || offsets.size() > 3) + return invalidSeconds(); // No numbers, or too many. + + qint32 seconds = 0; + int prior = 0; // Number of fields parsed thus far + for (const auto &offset : offsets) { + bool ok = false; + unsigned short field = offset.toUShort(&ok); + // Bound hour above at 24, minutes and seconds at 60: + if (!ok || field >= (prior ? 60 : 24)) + return invalidSeconds(); + seconds = seconds * 60 + field; + ++prior; + } + while (prior++ < 3) + seconds *= 60; + + return seconds * sign; +} + // Create offset from UTC QUtcTimeZonePrivate::QUtcTimeZonePrivate(qint32 offsetSeconds) { @@ -877,22 +911,25 @@ QByteArray QUtcTimeZonePrivate::systemTimeZoneId() const bool QUtcTimeZonePrivate::isTimeZoneIdAvailable(const QByteArray &ianaId) const { + // Only the zone IDs supplied by CLDR and recognized by constructor. for (int i = 0; i < utcDataTableSize; ++i) { const QUtcData *data = utcData(i); - if (utcId(data) == ianaId) { + if (utcId(data) == ianaId) return true; - } } + // But see offsetFromUtcString(), which lets us accept some "unavailable" IDs. return false; } QList<QByteArray> QUtcTimeZonePrivate::availableTimeZoneIds() const { + // Only the zone IDs supplied by CLDR and recognized by constructor. QList<QByteArray> result; result.reserve(utcDataTableSize); for (int i = 0; i < utcDataTableSize; ++i) result << utcId(utcData(i)); - std::sort(result.begin(), result.end()); // ### or already sorted?? + // Not guaranteed to be sorted, so sort: + std::sort(result.begin(), result.end()); // ### assuming no duplicates return result; } @@ -907,13 +944,16 @@ QList<QByteArray> QUtcTimeZonePrivate::availableTimeZoneIds(QLocale::Country cou QList<QByteArray> QUtcTimeZonePrivate::availableTimeZoneIds(qint32 offsetSeconds) const { + // Only if it's present in CLDR. (May get more than one ID: UTC, UTC+00:00 + // and UTC-00:00 all have the same offset.) QList<QByteArray> result; for (int i = 0; i < utcDataTableSize; ++i) { const QUtcData *data = utcData(i); if (data->offsetFromUtc == offsetSeconds) result << utcId(data); } - std::sort(result.begin(), result.end()); // ### or already sorted?? + // Not guaranteed to be sorted, so sort: + std::sort(result.begin(), result.end()); // ### assuming no duplicates return result; } |