qt5-*.güncellendi
This commit is contained in:
		
							parent
							
								
									914ff6acac
								
							
						
					
					
						commit
						adad4ce64e
					
				
					 3 changed files with 0 additions and 484 deletions
				
			
		| 
						 | 
					@ -1,272 +0,0 @@
 | 
				
			||||||
From e9041c7fc1052167f1ec2df0ea9623059e55d00f Mon Sep 17 00:00:00 2001
 | 
					 | 
				
			||||||
From: Thiago Macieira <thiago.macieira@intel.com>
 | 
					 | 
				
			||||||
Date: Thu, 28 Apr 2016 22:09:01 -0700
 | 
					 | 
				
			||||||
Subject: [PATCH] Fix parsing of tzfile(5) POSIX rule zone names with bracket
 | 
					 | 
				
			||||||
 quotes
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
POSIX.1-2001 allows quoting a zone name so that it can contain other
 | 
					 | 
				
			||||||
characters besides letters, by enclosing it in angle brackets ('<' and
 | 
					 | 
				
			||||||
'>'). This hadn't been used until recently (tzdata2016b), when the
 | 
					 | 
				
			||||||
Asia/Barnaul rule started using a zone name "+07" (the name variable
 | 
					 | 
				
			||||||
contained the value "<+07>-7").
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Thanks to Paul Eggert for reporting and investigating the root cause.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Task-number: QTBUG-53071
 | 
					 | 
				
			||||||
Change-Id: Id5480807d25e49e78b79ffff1449bc410776cb66
 | 
					 | 
				
			||||||
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
 | 
					 | 
				
			||||||
Reviewed-by: Lars Knoll <lars.knoll@theqtcompany.com>
 | 
					 | 
				
			||||||
---
 | 
					 | 
				
			||||||
 src/corelib/tools/qtimezoneprivate_tz.cpp          | 176 ++++++++++++++-------
 | 
					 | 
				
			||||||
 .../auto/corelib/tools/qtimezone/tst_qtimezone.cpp |  10 ++
 | 
					 | 
				
			||||||
 2 files changed, 130 insertions(+), 56 deletions(-)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
diff --git a/src/corelib/tools/qtimezoneprivate_tz.cpp b/src/corelib/tools/qtimezoneprivate_tz.cpp
 | 
					 | 
				
			||||||
index 85ed345..cb9581a 100644
 | 
					 | 
				
			||||||
--- a/src/corelib/tools/qtimezoneprivate_tz.cpp
 | 
					 | 
				
			||||||
+++ b/src/corelib/tools/qtimezoneprivate_tz.cpp
 | 
					 | 
				
			||||||
@@ -41,6 +41,8 @@
 | 
					 | 
				
			||||||
 
 | 
					 | 
				
			||||||
 #include <qdebug.h>
 | 
					 | 
				
			||||||
 
 | 
					 | 
				
			||||||
+#include "qlocale_tools_p.h"
 | 
					 | 
				
			||||||
+
 | 
					 | 
				
			||||||
 #include <algorithm>
 | 
					 | 
				
			||||||
 
 | 
					 | 
				
			||||||
 QT_BEGIN_NAMESPACE
 | 
					 | 
				
			||||||
@@ -384,25 +386,100 @@ static QTime parsePosixTime(const QByteArray &timeRule)
 | 
					 | 
				
			||||||
     return QTime(2, 0, 0);
 | 
					 | 
				
			||||||
 }
 | 
					 | 
				
			||||||
 
 | 
					 | 
				
			||||||
-static int parsePosixOffset(const QByteArray &timeRule)
 | 
					 | 
				
			||||||
+static int parsePosixOffset(const char *begin, const char *end)
 | 
					 | 
				
			||||||
 {
 | 
					 | 
				
			||||||
     // Format "[+|-]hh[:mm[:ss]]"
 | 
					 | 
				
			||||||
-    QList<QByteArray> parts = timeRule.split(':');
 | 
					 | 
				
			||||||
-    int count = parts.count();
 | 
					 | 
				
			||||||
-    if (count == 3) {
 | 
					 | 
				
			||||||
-        int hour = parts.at(0).toInt();
 | 
					 | 
				
			||||||
-        int sign = hour >= 0 ? -1 : 1;
 | 
					 | 
				
			||||||
-        return sign * ((qAbs(hour) * 60 * 60) + (parts.at(1).toInt() * 60) + parts.at(2).toInt());
 | 
					 | 
				
			||||||
-    } else if (count == 2) {
 | 
					 | 
				
			||||||
-        int hour = parts.at(0).toInt();
 | 
					 | 
				
			||||||
-        int sign = hour >= 0 ? -1 : 1;
 | 
					 | 
				
			||||||
-        return sign * ((qAbs(hour) * 60 * 60) + (parts.at(1).toInt() * 60));
 | 
					 | 
				
			||||||
-    } else if (count == 1) {
 | 
					 | 
				
			||||||
-        int hour = parts.at(0).toInt();
 | 
					 | 
				
			||||||
-        int sign = hour >= 0 ? -1 : 1;
 | 
					 | 
				
			||||||
-        return sign * (qAbs(hour) * 60 * 60);
 | 
					 | 
				
			||||||
-    }
 | 
					 | 
				
			||||||
-    return 0;
 | 
					 | 
				
			||||||
+    int hour, min = 0, sec = 0;
 | 
					 | 
				
			||||||
+
 | 
					 | 
				
			||||||
+    // note that the sign is inverted because POSIX counts in hours West of GMT
 | 
					 | 
				
			||||||
+    bool negate = true;
 | 
					 | 
				
			||||||
+    if (*begin == '+') {
 | 
					 | 
				
			||||||
+        ++begin;
 | 
					 | 
				
			||||||
+    } else if (*begin == '-') {
 | 
					 | 
				
			||||||
+        negate = false;
 | 
					 | 
				
			||||||
+        ++begin;
 | 
					 | 
				
			||||||
+    }
 | 
					 | 
				
			||||||
+
 | 
					 | 
				
			||||||
+    bool ok = false;
 | 
					 | 
				
			||||||
+    hour = qstrtoll(begin, &begin, 10, &ok);
 | 
					 | 
				
			||||||
+    if (!ok)
 | 
					 | 
				
			||||||
+        return INT_MIN;
 | 
					 | 
				
			||||||
+    if (begin < end && *begin == ':') {
 | 
					 | 
				
			||||||
+        // minutes
 | 
					 | 
				
			||||||
+        ++begin;
 | 
					 | 
				
			||||||
+        min = qstrtoll(begin, &begin, 10, &ok);
 | 
					 | 
				
			||||||
+        if (!ok || min < 0)
 | 
					 | 
				
			||||||
+            return INT_MIN;
 | 
					 | 
				
			||||||
+
 | 
					 | 
				
			||||||
+        if (begin < end && *begin == ':') {
 | 
					 | 
				
			||||||
+            // seconds
 | 
					 | 
				
			||||||
+            ++begin;
 | 
					 | 
				
			||||||
+            sec = qstrtoll(begin, &begin, 10, &ok);
 | 
					 | 
				
			||||||
+            if (!ok || sec < 0)
 | 
					 | 
				
			||||||
+                return INT_MIN;
 | 
					 | 
				
			||||||
+        }
 | 
					 | 
				
			||||||
+    }
 | 
					 | 
				
			||||||
+
 | 
					 | 
				
			||||||
+    // we must have consumed everything
 | 
					 | 
				
			||||||
+    if (begin != end)
 | 
					 | 
				
			||||||
+        return INT_MIN;
 | 
					 | 
				
			||||||
+
 | 
					 | 
				
			||||||
+    int value = (hour * 60 + min) * 60 + sec;
 | 
					 | 
				
			||||||
+    return negate ? -value : value;
 | 
					 | 
				
			||||||
+}
 | 
					 | 
				
			||||||
+
 | 
					 | 
				
			||||||
+static inline bool asciiIsLetter(char ch)
 | 
					 | 
				
			||||||
+{
 | 
					 | 
				
			||||||
+    ch |= 0x20; // lowercases if it is a letter, otherwise just corrupts ch
 | 
					 | 
				
			||||||
+    return ch >= 'a' && ch <= 'z';
 | 
					 | 
				
			||||||
+}
 | 
					 | 
				
			||||||
+
 | 
					 | 
				
			||||||
+// Returns the zone name, the offset (in seconds) and advances \a begin to
 | 
					 | 
				
			||||||
+// where the parsing ended. Returns a zone of INT_MIN in case an offset
 | 
					 | 
				
			||||||
+// couldn't be read.
 | 
					 | 
				
			||||||
+static QPair<QString, int> parsePosixZoneNameAndOffset(const char *&pos, const char *end)
 | 
					 | 
				
			||||||
+{
 | 
					 | 
				
			||||||
+    static const char offsetChars[] = "0123456789:";
 | 
					 | 
				
			||||||
+    QPair<QString, int> result = qMakePair(QString(), INT_MIN);
 | 
					 | 
				
			||||||
+
 | 
					 | 
				
			||||||
+    const char *nameBegin = pos;
 | 
					 | 
				
			||||||
+    const char *nameEnd;
 | 
					 | 
				
			||||||
+    Q_ASSERT(pos < end);
 | 
					 | 
				
			||||||
+
 | 
					 | 
				
			||||||
+    if (*pos == '<') {
 | 
					 | 
				
			||||||
+        nameBegin = pos + 1;    // skip the '<'
 | 
					 | 
				
			||||||
+        nameEnd = nameBegin;
 | 
					 | 
				
			||||||
+        while (nameEnd < end && *nameEnd != '>') {
 | 
					 | 
				
			||||||
+            // POSIX says only alphanumeric, but we allow anything
 | 
					 | 
				
			||||||
+            ++nameEnd;
 | 
					 | 
				
			||||||
+        }
 | 
					 | 
				
			||||||
+        pos = nameEnd + 1;      // skip the '>'
 | 
					 | 
				
			||||||
+    } else {
 | 
					 | 
				
			||||||
+        nameBegin = pos;
 | 
					 | 
				
			||||||
+        nameEnd = nameBegin;
 | 
					 | 
				
			||||||
+        while (nameEnd < end && asciiIsLetter(*nameEnd))
 | 
					 | 
				
			||||||
+            ++nameEnd;
 | 
					 | 
				
			||||||
+        pos = nameEnd;
 | 
					 | 
				
			||||||
+    }
 | 
					 | 
				
			||||||
+    if (nameEnd - nameBegin < 3)
 | 
					 | 
				
			||||||
+        return result;  // name must be at least 3 characters long
 | 
					 | 
				
			||||||
+
 | 
					 | 
				
			||||||
+    // zone offset, form [+-]hh:mm:ss
 | 
					 | 
				
			||||||
+    const char *zoneBegin = pos;
 | 
					 | 
				
			||||||
+    const char *zoneEnd = pos;
 | 
					 | 
				
			||||||
+    if (zoneEnd < end && (zoneEnd[0] == '+' || zoneEnd[0] == '-'))
 | 
					 | 
				
			||||||
+        ++zoneEnd;
 | 
					 | 
				
			||||||
+    while (zoneEnd < end) {
 | 
					 | 
				
			||||||
+        if (strchr(offsetChars, char(*zoneEnd)) == NULL)
 | 
					 | 
				
			||||||
+            break;
 | 
					 | 
				
			||||||
+        ++zoneEnd;
 | 
					 | 
				
			||||||
+    }
 | 
					 | 
				
			||||||
+
 | 
					 | 
				
			||||||
+    result.first = QString::fromUtf8(nameBegin, nameEnd - nameBegin);
 | 
					 | 
				
			||||||
+    if (zoneEnd > zoneBegin)
 | 
					 | 
				
			||||||
+        result.second = parsePosixOffset(zoneBegin, zoneEnd);
 | 
					 | 
				
			||||||
+    pos = zoneEnd;
 | 
					 | 
				
			||||||
+    return result;
 | 
					 | 
				
			||||||
 }
 | 
					 | 
				
			||||||
 
 | 
					 | 
				
			||||||
 static QVector<QTimeZonePrivate::Data> calculatePosixTransitions(const QByteArray &posixRule,
 | 
					 | 
				
			||||||
@@ -419,51 +496,38 @@ static QVector<QTimeZonePrivate::Data> calculatePosixTransitions(const QByteArra
 | 
					 | 
				
			||||||
 
 | 
					 | 
				
			||||||
     // POSIX Format is like "TZ=CST6CDT,M3.2.0/2:00:00,M11.1.0/2:00:00"
 | 
					 | 
				
			||||||
     // i.e. "std offset dst [offset],start[/time],end[/time]"
 | 
					 | 
				
			||||||
-    // See http://www.gnu.org/software/libc/manual/html_node/TZ-Variable.html
 | 
					 | 
				
			||||||
+    // See the section about TZ at http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html
 | 
					 | 
				
			||||||
     QList<QByteArray> parts = posixRule.split(',');
 | 
					 | 
				
			||||||
 
 | 
					 | 
				
			||||||
-    QString name = QString::fromUtf8(parts.at(0));
 | 
					 | 
				
			||||||
-    QString stdName;
 | 
					 | 
				
			||||||
-    QString stdOffsetString;
 | 
					 | 
				
			||||||
-    QString dstName;
 | 
					 | 
				
			||||||
-    QString dstOffsetString;
 | 
					 | 
				
			||||||
-    bool parsedStdName = false;
 | 
					 | 
				
			||||||
-    bool parsedStdOffset = false;
 | 
					 | 
				
			||||||
-    for (int i = 0; i < name.size(); ++i) {
 | 
					 | 
				
			||||||
-        if (name.at(i).isLetter()) {
 | 
					 | 
				
			||||||
-            if (parsedStdName) {
 | 
					 | 
				
			||||||
-                parsedStdOffset = true;
 | 
					 | 
				
			||||||
-                dstName.append(name.at(i));
 | 
					 | 
				
			||||||
-            } else {
 | 
					 | 
				
			||||||
-                stdName.append(name.at(i));
 | 
					 | 
				
			||||||
+    QPair<QString, int> stdZone, dstZone;
 | 
					 | 
				
			||||||
+    {
 | 
					 | 
				
			||||||
+        const QByteArray &zoneinfo = parts.at(0);
 | 
					 | 
				
			||||||
+        const char *begin = zoneinfo.constBegin();
 | 
					 | 
				
			||||||
+
 | 
					 | 
				
			||||||
+        stdZone = parsePosixZoneNameAndOffset(begin, zoneinfo.constEnd());
 | 
					 | 
				
			||||||
+        if (stdZone.second == INT_MIN) {
 | 
					 | 
				
			||||||
+            stdZone.second = 0;     // reset to UTC if we failed to parse
 | 
					 | 
				
			||||||
+        } else if (begin < zoneinfo.constEnd()) {
 | 
					 | 
				
			||||||
+            dstZone = parsePosixZoneNameAndOffset(begin, zoneinfo.constEnd());
 | 
					 | 
				
			||||||
+            if (dstZone.second == INT_MIN) {
 | 
					 | 
				
			||||||
+                // if the dst offset isn't provided, it is 1 hour ahead of the standard offset
 | 
					 | 
				
			||||||
+                dstZone.second = stdZone.second + (60 * 60);
 | 
					 | 
				
			||||||
             }
 | 
					 | 
				
			||||||
-        } else {
 | 
					 | 
				
			||||||
-            parsedStdName = true;
 | 
					 | 
				
			||||||
-            if (parsedStdOffset)
 | 
					 | 
				
			||||||
-                dstOffsetString.append(name.at(i));
 | 
					 | 
				
			||||||
-            else
 | 
					 | 
				
			||||||
-                stdOffsetString.append(name.at(i));
 | 
					 | 
				
			||||||
         }
 | 
					 | 
				
			||||||
     }
 | 
					 | 
				
			||||||
 
 | 
					 | 
				
			||||||
-    int utcOffset = parsePosixOffset(stdOffsetString.toUtf8());
 | 
					 | 
				
			||||||
-
 | 
					 | 
				
			||||||
     // If only the name part then no transitions
 | 
					 | 
				
			||||||
     if (parts.count() == 1) {
 | 
					 | 
				
			||||||
         QTimeZonePrivate::Data data;
 | 
					 | 
				
			||||||
         data.atMSecsSinceEpoch = lastTranMSecs;
 | 
					 | 
				
			||||||
-        data.offsetFromUtc = utcOffset;
 | 
					 | 
				
			||||||
-        data.standardTimeOffset = utcOffset;
 | 
					 | 
				
			||||||
+        data.offsetFromUtc = stdZone.second;
 | 
					 | 
				
			||||||
+        data.standardTimeOffset = stdZone.second;
 | 
					 | 
				
			||||||
         data.daylightTimeOffset = 0;
 | 
					 | 
				
			||||||
-        data.abbreviation = stdName;
 | 
					 | 
				
			||||||
+        data.abbreviation = stdZone.first;
 | 
					 | 
				
			||||||
         result << data;
 | 
					 | 
				
			||||||
         return result;
 | 
					 | 
				
			||||||
     }
 | 
					 | 
				
			||||||
 
 | 
					 | 
				
			||||||
-    // If not populated the total dst offset is 1 hour
 | 
					 | 
				
			||||||
-    int dstOffset = utcOffset + (60 * 60);
 | 
					 | 
				
			||||||
-    if (!dstOffsetString.isEmpty())
 | 
					 | 
				
			||||||
-        dstOffset = parsePosixOffset(dstOffsetString.toUtf8());
 | 
					 | 
				
			||||||
 
 | 
					 | 
				
			||||||
     // Get the std to dst transtion details
 | 
					 | 
				
			||||||
     QList<QByteArray> dstParts = parts.at(1).split('/');
 | 
					 | 
				
			||||||
@@ -486,18 +550,18 @@ static QVector<QTimeZonePrivate::Data> calculatePosixTransitions(const QByteArra
 | 
					 | 
				
			||||||
     for (int year = startYear; year <= endYear; ++year) {
 | 
					 | 
				
			||||||
         QTimeZonePrivate::Data dstData;
 | 
					 | 
				
			||||||
         QDateTime dst(calculatePosixDate(dstDateRule, year), dstTime, Qt::UTC);
 | 
					 | 
				
			||||||
-        dstData.atMSecsSinceEpoch = dst.toMSecsSinceEpoch() - (utcOffset * 1000);
 | 
					 | 
				
			||||||
-        dstData.offsetFromUtc = dstOffset;
 | 
					 | 
				
			||||||
-        dstData.standardTimeOffset = utcOffset;
 | 
					 | 
				
			||||||
-        dstData.daylightTimeOffset = dstOffset - utcOffset;
 | 
					 | 
				
			||||||
-        dstData.abbreviation = dstName;
 | 
					 | 
				
			||||||
+        dstData.atMSecsSinceEpoch = dst.toMSecsSinceEpoch() - (stdZone.second * 1000);
 | 
					 | 
				
			||||||
+        dstData.offsetFromUtc = dstZone.second;
 | 
					 | 
				
			||||||
+        dstData.standardTimeOffset = stdZone.second;
 | 
					 | 
				
			||||||
+        dstData.daylightTimeOffset = dstZone.second - stdZone.second;
 | 
					 | 
				
			||||||
+        dstData.abbreviation = dstZone.first;
 | 
					 | 
				
			||||||
         QTimeZonePrivate::Data stdData;
 | 
					 | 
				
			||||||
         QDateTime std(calculatePosixDate(stdDateRule, year), stdTime, Qt::UTC);
 | 
					 | 
				
			||||||
-        stdData.atMSecsSinceEpoch = std.toMSecsSinceEpoch() - (dstOffset * 1000);
 | 
					 | 
				
			||||||
-        stdData.offsetFromUtc = utcOffset;
 | 
					 | 
				
			||||||
-        stdData.standardTimeOffset = utcOffset;
 | 
					 | 
				
			||||||
+        stdData.atMSecsSinceEpoch = std.toMSecsSinceEpoch() - (dstZone.second * 1000);
 | 
					 | 
				
			||||||
+        stdData.offsetFromUtc = stdZone.second;
 | 
					 | 
				
			||||||
+        stdData.standardTimeOffset = stdZone.second;
 | 
					 | 
				
			||||||
         stdData.daylightTimeOffset = 0;
 | 
					 | 
				
			||||||
-        stdData.abbreviation = stdName;
 | 
					 | 
				
			||||||
+        stdData.abbreviation = stdZone.first;
 | 
					 | 
				
			||||||
         // Part of the high year will overflow
 | 
					 | 
				
			||||||
         if (year == 292278994 && (dstData.atMSecsSinceEpoch < 0 || stdData.atMSecsSinceEpoch < 0)) {
 | 
					 | 
				
			||||||
             if (dstData.atMSecsSinceEpoch > 0) {
 | 
					 | 
				
			||||||
diff --git a/tests/auto/corelib/tools/qtimezone/tst_qtimezone.cpp b/tests/auto/corelib/tools/qtimezone/tst_qtimezone.cpp
 | 
					 | 
				
			||||||
index ea83510..ce72e7c 100644
 | 
					 | 
				
			||||||
--- a/tests/auto/corelib/tools/qtimezone/tst_qtimezone.cpp
 | 
					 | 
				
			||||||
+++ b/tests/auto/corelib/tools/qtimezone/tst_qtimezone.cpp
 | 
					 | 
				
			||||||
@@ -847,6 +847,16 @@ void tst_QTimeZone::tzTest()
 | 
					 | 
				
			||||||
     QTzTimeZonePrivate::Data datatz2 = tztz2.data(std);
 | 
					 | 
				
			||||||
     QTzTimeZonePrivate::Data datautc2 = tzutc2.data(std);
 | 
					 | 
				
			||||||
     QCOMPARE(datatz2.offsetFromUtc, datautc2.offsetFromUtc);
 | 
					 | 
				
			||||||
+
 | 
					 | 
				
			||||||
+    // Test a timezone with a name that isn't all letters
 | 
					 | 
				
			||||||
+    QTzTimeZonePrivate tzBarnaul("Asia/Barnaul");
 | 
					 | 
				
			||||||
+    if (tzBarnaul.isValid()) {
 | 
					 | 
				
			||||||
+        QCOMPARE(tzBarnaul.data(std).abbreviation, QString("+07"));
 | 
					 | 
				
			||||||
+
 | 
					 | 
				
			||||||
+        // first full day of the new rule (tzdata2016b)
 | 
					 | 
				
			||||||
+        QDateTime dt(QDate(2016, 3, 28), QTime(0, 0, 0), Qt::UTC);
 | 
					 | 
				
			||||||
+        QCOMPARE(tzBarnaul.data(dt.toMSecsSinceEpoch()).abbreviation, QString("+07"));
 | 
					 | 
				
			||||||
+    }
 | 
					 | 
				
			||||||
 #endif // Q_OS_UNIX
 | 
					 | 
				
			||||||
 }
 | 
					 | 
				
			||||||
 
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,122 +0,0 @@
 | 
				
			||||||
From cd25866f6533923c208f52d58516f3725f69cefb Mon Sep 17 00:00:00 2001
 | 
					 | 
				
			||||||
From: Thiago Macieira <thiago.macieira@intel.com>
 | 
					 | 
				
			||||||
Date: Wed, 18 May 2016 13:38:55 -0700
 | 
					 | 
				
			||||||
Subject: [PATCH] Use the code we already have for parsing the transition time
 | 
					 | 
				
			||||||
 too
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
It's there and it's more efficient anyway.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Change-Id: Ie9fd7afe060b4e4a8052fffd144fc40647430268
 | 
					 | 
				
			||||||
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
 | 
					 | 
				
			||||||
Reviewed-by: Brett Stottlemyer <bstottle@ford.com>
 | 
					 | 
				
			||||||
Reviewed-by: Lars Knoll <lars.knoll@theqtcompany.com>
 | 
					 | 
				
			||||||
---
 | 
					 | 
				
			||||||
 src/corelib/tools/qtimezoneprivate_tz.cpp | 68 ++++++++++++++++++-------------
 | 
					 | 
				
			||||||
 1 file changed, 40 insertions(+), 28 deletions(-)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
diff --git a/src/corelib/tools/qtimezoneprivate_tz.cpp b/src/corelib/tools/qtimezoneprivate_tz.cpp
 | 
					 | 
				
			||||||
index cb9581a..bfa967e 100644
 | 
					 | 
				
			||||||
--- a/src/corelib/tools/qtimezoneprivate_tz.cpp
 | 
					 | 
				
			||||||
+++ b/src/corelib/tools/qtimezoneprivate_tz.cpp
 | 
					 | 
				
			||||||
@@ -372,37 +372,21 @@ static QDate calculatePosixDate(const QByteArray &dateRule, int year)
 | 
					 | 
				
			||||||
     }
 | 
					 | 
				
			||||||
 }
 | 
					 | 
				
			||||||
 
 | 
					 | 
				
			||||||
-static QTime parsePosixTime(const QByteArray &timeRule)
 | 
					 | 
				
			||||||
+// returns the time in seconds, INT_MIN if we failed to parse
 | 
					 | 
				
			||||||
+static int parsePosixTime(const char *begin, const char *end)
 | 
					 | 
				
			||||||
 {
 | 
					 | 
				
			||||||
-    // Format "HH:mm:ss", put check parts count just in case
 | 
					 | 
				
			||||||
-    QList<QByteArray> parts = timeRule.split(':');
 | 
					 | 
				
			||||||
-    int count = parts.count();
 | 
					 | 
				
			||||||
-    if (count == 3)
 | 
					 | 
				
			||||||
-        return QTime(parts.at(0).toInt(), parts.at(1).toInt(), parts.at(2).toInt());
 | 
					 | 
				
			||||||
-    else if (count == 2)
 | 
					 | 
				
			||||||
-        return QTime(parts.at(0).toInt(), parts.at(1).toInt(), 0);
 | 
					 | 
				
			||||||
-    else if (count == 1)
 | 
					 | 
				
			||||||
-        return QTime(parts.at(0).toInt(), 0, 0);
 | 
					 | 
				
			||||||
-    return QTime(2, 0, 0);
 | 
					 | 
				
			||||||
-}
 | 
					 | 
				
			||||||
-
 | 
					 | 
				
			||||||
-static int parsePosixOffset(const char *begin, const char *end)
 | 
					 | 
				
			||||||
-{
 | 
					 | 
				
			||||||
-    // Format "[+|-]hh[:mm[:ss]]"
 | 
					 | 
				
			||||||
+    // Format "hh[:mm[:ss]]"
 | 
					 | 
				
			||||||
     int hour, min = 0, sec = 0;
 | 
					 | 
				
			||||||
 
 | 
					 | 
				
			||||||
-    // note that the sign is inverted because POSIX counts in hours West of GMT
 | 
					 | 
				
			||||||
-    bool negate = true;
 | 
					 | 
				
			||||||
-    if (*begin == '+') {
 | 
					 | 
				
			||||||
-        ++begin;
 | 
					 | 
				
			||||||
-    } else if (*begin == '-') {
 | 
					 | 
				
			||||||
-        negate = false;
 | 
					 | 
				
			||||||
-        ++begin;
 | 
					 | 
				
			||||||
-    }
 | 
					 | 
				
			||||||
+    // Note that the calls to qstrtoll do *not* check the end pointer, which
 | 
					 | 
				
			||||||
+    // means they proceed until they find a non-digit. We check that we're
 | 
					 | 
				
			||||||
+    // still in range at the end, but we may have read from past end. It's the
 | 
					 | 
				
			||||||
+    // caller's responsibility to ensure that begin is part of a
 | 
					 | 
				
			||||||
+    // null-terminated string.
 | 
					 | 
				
			||||||
 
 | 
					 | 
				
			||||||
     bool ok = false;
 | 
					 | 
				
			||||||
     hour = qstrtoll(begin, &begin, 10, &ok);
 | 
					 | 
				
			||||||
-    if (!ok)
 | 
					 | 
				
			||||||
+    if (!ok || hour < 0)
 | 
					 | 
				
			||||||
         return INT_MIN;
 | 
					 | 
				
			||||||
     if (begin < end && *begin == ':') {
 | 
					 | 
				
			||||||
         // minutes
 | 
					 | 
				
			||||||
@@ -424,7 +408,35 @@ static int parsePosixOffset(const char *begin, const char *end)
 | 
					 | 
				
			||||||
     if (begin != end)
 | 
					 | 
				
			||||||
         return INT_MIN;
 | 
					 | 
				
			||||||
 
 | 
					 | 
				
			||||||
-    int value = (hour * 60 + min) * 60 + sec;
 | 
					 | 
				
			||||||
+    return (hour * 60 + min) * 60 + sec;
 | 
					 | 
				
			||||||
+}
 | 
					 | 
				
			||||||
+
 | 
					 | 
				
			||||||
+static QTime parsePosixTransitionTime(const QByteArray &timeRule)
 | 
					 | 
				
			||||||
+{
 | 
					 | 
				
			||||||
+    // Format "hh[:mm[:ss]]"
 | 
					 | 
				
			||||||
+    int value = parsePosixTime(timeRule.constBegin(), timeRule.constEnd());
 | 
					 | 
				
			||||||
+    if (value == INT_MIN) {
 | 
					 | 
				
			||||||
+        // if we failed to parse, return 02:00
 | 
					 | 
				
			||||||
+        return QTime(2, 0, 0);
 | 
					 | 
				
			||||||
+    }
 | 
					 | 
				
			||||||
+    return QTime::fromMSecsSinceStartOfDay(value * 1000);
 | 
					 | 
				
			||||||
+}
 | 
					 | 
				
			||||||
+
 | 
					 | 
				
			||||||
+static int parsePosixOffset(const char *begin, const char *end)
 | 
					 | 
				
			||||||
+{
 | 
					 | 
				
			||||||
+    // Format "[+|-]hh[:mm[:ss]]"
 | 
					 | 
				
			||||||
+    // note that the sign is inverted because POSIX counts in hours West of GMT
 | 
					 | 
				
			||||||
+    bool negate = true;
 | 
					 | 
				
			||||||
+    if (*begin == '+') {
 | 
					 | 
				
			||||||
+        ++begin;
 | 
					 | 
				
			||||||
+    } else if (*begin == '-') {
 | 
					 | 
				
			||||||
+        negate = false;
 | 
					 | 
				
			||||||
+        ++begin;
 | 
					 | 
				
			||||||
+    }
 | 
					 | 
				
			||||||
+
 | 
					 | 
				
			||||||
+    int value = parsePosixTime(begin, end);
 | 
					 | 
				
			||||||
+    if (value == INT_MIN)
 | 
					 | 
				
			||||||
+        return value;
 | 
					 | 
				
			||||||
     return negate ? -value : value;
 | 
					 | 
				
			||||||
 }
 | 
					 | 
				
			||||||
 
 | 
					 | 
				
			||||||
@@ -534,7 +546,7 @@ static QVector<QTimeZonePrivate::Data> calculatePosixTransitions(const QByteArra
 | 
					 | 
				
			||||||
     QByteArray dstDateRule = dstParts.at(0);
 | 
					 | 
				
			||||||
     QTime dstTime;
 | 
					 | 
				
			||||||
     if (dstParts.count() > 1)
 | 
					 | 
				
			||||||
-        dstTime = parsePosixTime(dstParts.at(1));
 | 
					 | 
				
			||||||
+        dstTime = parsePosixTransitionTime(dstParts.at(1));
 | 
					 | 
				
			||||||
     else
 | 
					 | 
				
			||||||
         dstTime = QTime(2, 0, 0);
 | 
					 | 
				
			||||||
 
 | 
					 | 
				
			||||||
@@ -543,7 +555,7 @@ static QVector<QTimeZonePrivate::Data> calculatePosixTransitions(const QByteArra
 | 
					 | 
				
			||||||
     QByteArray stdDateRule = stdParts.at(0);
 | 
					 | 
				
			||||||
     QTime stdTime;
 | 
					 | 
				
			||||||
     if (stdParts.count() > 1)
 | 
					 | 
				
			||||||
-        stdTime = parsePosixTime(stdParts.at(1));
 | 
					 | 
				
			||||||
+        stdTime = parsePosixTransitionTime(stdParts.at(1));
 | 
					 | 
				
			||||||
     else
 | 
					 | 
				
			||||||
         stdTime = QTime(2, 0, 0);
 | 
					 | 
				
			||||||
 
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,90 +0,0 @@
 | 
				
			||||||
From 8e889378115c69508b050a511621ac8e30ec4158 Mon Sep 17 00:00:00 2001
 | 
					 | 
				
			||||||
From: Jesus Fernandez <jesus.fernandez@theqtcompany.com>
 | 
					 | 
				
			||||||
Date: Mon, 13 Jun 2016 19:09:15 +0200
 | 
					 | 
				
			||||||
Subject: [PATCH] Fix UNSIGNED values in QMYSQL
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
The unsigned flag in columns was ignored when creating the list of
 | 
					 | 
				
			||||||
bound values in a mysql table. So the result iteration with
 | 
					 | 
				
			||||||
QSqlQuery::next stops after the first wrong truncated value.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[ChangeLog][QtSql] Fixed QSqlQuery::prepare value truncation error when
 | 
					 | 
				
			||||||
using UNSIGNED values in a MySQL database.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Task-number: QTBUG-53969
 | 
					 | 
				
			||||||
Task-number: QTBUG-53237
 | 
					 | 
				
			||||||
Change-Id: I10d977993445f2794f1dd8c88b2e83517ef524f3
 | 
					 | 
				
			||||||
Reviewed-by: Milian Wolff <milian.wolff@kdab.com>
 | 
					 | 
				
			||||||
---
 | 
					 | 
				
			||||||
 src/sql/drivers/mysql/qsql_mysql.cpp              |  1 +
 | 
					 | 
				
			||||||
 tests/auto/sql/kernel/qsqlquery/tst_qsqlquery.cpp | 39 +++++++++++++++++++++++
 | 
					 | 
				
			||||||
 2 files changed, 40 insertions(+)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
diff --git a/src/sql/drivers/mysql/qsql_mysql.cpp b/src/sql/drivers/mysql/qsql_mysql.cpp
 | 
					 | 
				
			||||||
index 96bdcc4..55bf499 100644
 | 
					 | 
				
			||||||
--- a/src/sql/drivers/mysql/qsql_mysql.cpp
 | 
					 | 
				
			||||||
+++ b/src/sql/drivers/mysql/qsql_mysql.cpp
 | 
					 | 
				
			||||||
@@ -387,6 +387,7 @@ bool QMYSQLResultPrivate::bindInValues()
 | 
					 | 
				
			||||||
         bind->buffer_length = f.bufLength = fieldInfo->length + 1;
 | 
					 | 
				
			||||||
         bind->is_null = &f.nullIndicator;
 | 
					 | 
				
			||||||
         bind->length = &f.bufLength;
 | 
					 | 
				
			||||||
+        bind->is_unsigned = fieldInfo->flags & UNSIGNED_FLAG ? 1 : 0;
 | 
					 | 
				
			||||||
         f.outField=field;
 | 
					 | 
				
			||||||
 
 | 
					 | 
				
			||||||
         ++i;
 | 
					 | 
				
			||||||
diff --git a/tests/auto/sql/kernel/qsqlquery/tst_qsqlquery.cpp b/tests/auto/sql/kernel/qsqlquery/tst_qsqlquery.cpp
 | 
					 | 
				
			||||||
index bd553d5..f1c4333 100644
 | 
					 | 
				
			||||||
--- a/tests/auto/sql/kernel/qsqlquery/tst_qsqlquery.cpp
 | 
					 | 
				
			||||||
+++ b/tests/auto/sql/kernel/qsqlquery/tst_qsqlquery.cpp
 | 
					 | 
				
			||||||
@@ -233,6 +233,9 @@ private slots:
 | 
					 | 
				
			||||||
     void QTBUG_36211_data() { generic_data("QPSQL"); }
 | 
					 | 
				
			||||||
     void QTBUG_36211();
 | 
					 | 
				
			||||||
 
 | 
					 | 
				
			||||||
+    void QTBUG_53969_data() { generic_data("QMYSQL"); }
 | 
					 | 
				
			||||||
+    void QTBUG_53969();
 | 
					 | 
				
			||||||
+
 | 
					 | 
				
			||||||
     void sqlite_constraint_data() { generic_data("QSQLITE"); }
 | 
					 | 
				
			||||||
     void sqlite_constraint();
 | 
					 | 
				
			||||||
 
 | 
					 | 
				
			||||||
@@ -3652,6 +3655,42 @@ void tst_QSqlQuery::QTBUG_36211()
 | 
					 | 
				
			||||||
     }
 | 
					 | 
				
			||||||
 }
 | 
					 | 
				
			||||||
 
 | 
					 | 
				
			||||||
+void tst_QSqlQuery::QTBUG_53969()
 | 
					 | 
				
			||||||
+{
 | 
					 | 
				
			||||||
+    QFETCH( QString, dbName );
 | 
					 | 
				
			||||||
+    QVector<int> values = QVector<int>() << 10 << 20 << 127 << 128 << 1, tableValues;
 | 
					 | 
				
			||||||
+    QSqlDatabase db = QSqlDatabase::database( dbName );
 | 
					 | 
				
			||||||
+    CHECK_DATABASE( db );
 | 
					 | 
				
			||||||
+    tableValues.reserve(values.size());
 | 
					 | 
				
			||||||
+    if (tst_Databases::getDatabaseType(db) == QSqlDriver::MySqlServer) {
 | 
					 | 
				
			||||||
+        const QString tableName(qTableName("bug53969", __FILE__, db));
 | 
					 | 
				
			||||||
+        tst_Databases::safeDropTable( db, tableName );
 | 
					 | 
				
			||||||
+
 | 
					 | 
				
			||||||
+        QSqlQuery q(db);
 | 
					 | 
				
			||||||
+        QVERIFY_SQL(q, exec(QString("CREATE TABLE %1 (id INT AUTO_INCREMENT PRIMARY KEY, "
 | 
					 | 
				
			||||||
+                                    "test_number TINYINT(3) UNSIGNED)")
 | 
					 | 
				
			||||||
+                            .arg(tableName)));
 | 
					 | 
				
			||||||
+
 | 
					 | 
				
			||||||
+        QVERIFY_SQL(q, prepare("INSERT INTO " + tableName + " (test_number) VALUES (:value)"));
 | 
					 | 
				
			||||||
+
 | 
					 | 
				
			||||||
+        QVector<int>::iterator begin = values.begin(), end = values.end(), it;
 | 
					 | 
				
			||||||
+        for (it = begin; it != end; ++it) {
 | 
					 | 
				
			||||||
+            q.bindValue(":value", *it);
 | 
					 | 
				
			||||||
+            QVERIFY_SQL(q, exec());
 | 
					 | 
				
			||||||
+        }
 | 
					 | 
				
			||||||
+
 | 
					 | 
				
			||||||
+        QVERIFY_SQL(q, prepare("SELECT test_number FROM " + tableName));
 | 
					 | 
				
			||||||
+        QVERIFY_SQL(q, exec());
 | 
					 | 
				
			||||||
+
 | 
					 | 
				
			||||||
+        while (q.next()) {
 | 
					 | 
				
			||||||
+            bool ok;
 | 
					 | 
				
			||||||
+            tableValues.push_back(q.value(0).toUInt(&ok));
 | 
					 | 
				
			||||||
+            QVERIFY(ok);
 | 
					 | 
				
			||||||
+        }
 | 
					 | 
				
			||||||
+        QCOMPARE(values, tableValues);
 | 
					 | 
				
			||||||
+    }
 | 
					 | 
				
			||||||
+}
 | 
					 | 
				
			||||||
+
 | 
					 | 
				
			||||||
 void tst_QSqlQuery::oraOCINumber()
 | 
					 | 
				
			||||||
 {
 | 
					 | 
				
			||||||
     QFETCH( QString, dbName );
 | 
					 | 
				
			||||||
		Loading…
	
	Add table
		
		Reference in a new issue