summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--qmake/generators/win32/msvc_vcproj.cpp2
-rw-r--r--src/corelib/plugin/quuid.cpp156
-rw-r--r--src/corelib/plugin/quuid.h2
-rw-r--r--src/plugins/platforms/windows/qwindowsdialoghelpers.cpp2
-rw-r--r--tests/auto/corelib/plugin/quuid/tst_quuid.cpp56
-rw-r--r--tests/auto/corelib/plugin/quuid/tst_quuid_darwin.mm12
6 files changed, 154 insertions, 76 deletions
diff --git a/qmake/generators/win32/msvc_vcproj.cpp b/qmake/generators/win32/msvc_vcproj.cpp
index 48b8bea812..dfbb4c69ea 100644
--- a/qmake/generators/win32/msvc_vcproj.cpp
+++ b/qmake/generators/win32/msvc_vcproj.cpp
@@ -223,7 +223,7 @@ QUuid VcprojGenerator::getProjectUUID(const QString &filename)
bool validUUID = true;
// Read GUID from variable-space
- QUuid uuid = project->first("GUID").toQString();
+ auto uuid = QUuid::fromString(project->first("GUID").toQStringView());
// If none, create one based on the MD5 of absolute project path
if(uuid.isNull() || !filename.isEmpty()) {
diff --git a/src/corelib/plugin/quuid.cpp b/src/corelib/plugin/quuid.cpp
index 3b010b3ae1..c9644c73d3 100644
--- a/src/corelib/plugin/quuid.cpp
+++ b/src/corelib/plugin/quuid.cpp
@@ -67,8 +67,8 @@ void _q_toHex(char *&dst, Integral value)
}
}
-template <class Char, class Integral>
-bool _q_fromHex(const Char *&src, Integral &value)
+template <class Integral>
+bool _q_fromHex(const char *&src, Integral &value)
{
value = 0;
@@ -102,30 +102,46 @@ static char *_q_uuidToHex(const QUuid &uuid, char *dst)
return dst;
}
-template <class Char>
-bool _q_uuidFromHex(const Char *&src, uint &d1, ushort &d2, ushort &d3, uchar (&d4)[8])
+/*!
+ \internal
+
+ Parses the string representation of a UUID (with optional surrounding "{}")
+ by reading at most MaxStringUuidLength (38) characters from \a src, which
+ may be \c nullptr. Stops at the first invalid character (which includes a
+ premature NUL).
+
+ Returns the successfully parsed QUuid, or a null QUuid in case of failure.
+*/
+Q_NEVER_INLINE
+static QUuid _q_uuidFromHex(const char *src)
{
- if (*src == Char('{'))
- src++;
- if (!_q_fromHex(src, d1)
- || *src++ != Char('-')
- || !_q_fromHex(src, d2)
- || *src++ != Char('-')
- || !_q_fromHex(src, d3)
- || *src++ != Char('-')
- || !_q_fromHex(src, d4[0])
- || !_q_fromHex(src, d4[1])
- || *src++ != Char('-')
- || !_q_fromHex(src, d4[2])
- || !_q_fromHex(src, d4[3])
- || !_q_fromHex(src, d4[4])
- || !_q_fromHex(src, d4[5])
- || !_q_fromHex(src, d4[6])
- || !_q_fromHex(src, d4[7])) {
- return false;
+ uint d1;
+ ushort d2, d3;
+ uchar d4[8];
+
+ if (src) {
+ if (*src == '{')
+ src++;
+ if (Q_LIKELY( _q_fromHex(src, d1)
+ && *src++ == '-'
+ && _q_fromHex(src, d2)
+ && *src++ == '-'
+ && _q_fromHex(src, d3)
+ && *src++ == '-'
+ && _q_fromHex(src, d4[0])
+ && _q_fromHex(src, d4[1])
+ && *src++ == '-'
+ && _q_fromHex(src, d4[2])
+ && _q_fromHex(src, d4[3])
+ && _q_fromHex(src, d4[4])
+ && _q_fromHex(src, d4[5])
+ && _q_fromHex(src, d4[6])
+ && _q_fromHex(src, d4[7]))) {
+ return QUuid(d1, d2, d3, d4[0], d4[1], d4[2], d4[3], d4[4], d4[5], d4[6], d4[7]);
+ }
}
- return true;
+ return QUuid();
}
#ifndef QT_BOOTSTRAPPED
@@ -336,7 +352,7 @@ static QUuid createFromName(const QUuid &ns, const QByteArray &baseData, QCrypto
/*!
Creates a QUuid object from the string \a text, which must be
formatted as five hex fields separated by '-', e.g.,
- "{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}" where 'x' is a hex
+ "{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}" where each 'x' is a hex
digit. The curly braces shown here are optional, but it is normal to
include them. If the conversion fails, a null UUID is created. See
toString() for an explanation of how the five hex fields map to the
@@ -345,45 +361,76 @@ static QUuid createFromName(const QUuid &ns, const QByteArray &baseData, QCrypto
\sa toString(), QUuid()
*/
QUuid::QUuid(const QString &text)
+ : QUuid(fromString(text))
{
- if (text.length() < 36) {
- *this = QUuid();
- return;
- }
+}
+
+/*!
+ \since 5.10
- const ushort *data = reinterpret_cast<const ushort *>(text.unicode());
+ Creates a QUuid object from the string \a text, which must be
+ formatted as five hex fields separated by '-', e.g.,
+ "{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}" where each 'x' is a hex
+ digit. The curly braces shown here are optional, but it is normal to
+ include them. If the conversion fails, a null UUID is returned. See
+ toString() for an explanation of how the five hex fields map to the
+ public data members in QUuid.
- if (*data == '{' && text.length() < 37) {
- *this = QUuid();
- return;
- }
+ \sa toString(), QUuid()
+*/
+QUuid QUuid::fromString(QStringView text) Q_DECL_NOTHROW
+{
+ if (text.size() > MaxStringUuidLength)
+ text = text.left(MaxStringUuidLength); // text.truncate(MaxStringUuidLength);
- if (!_q_uuidFromHex(data, data1, data2, data3, data4)) {
- *this = QUuid();
- return;
+ char latin1[MaxStringUuidLength + 1];
+ char *dst = latin1;
+
+ for (QChar ch : text)
+ *dst++ = ch.toLatin1();
+
+ *dst++ = '\0'; // don't read garbage as potentially valid data
+
+ return _q_uuidFromHex(latin1);
+}
+
+/*!
+ \since 5.10
+ \overload
+
+ Creates a QUuid object from the string \a text, which must be
+ formatted as five hex fields separated by '-', e.g.,
+ "{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}" where each 'x' is a hex
+ digit. The curly braces shown here are optional, but it is normal to
+ include them. If the conversion fails, a null UUID is returned. See
+ toString() for an explanation of how the five hex fields map to the
+ public data members in QUuid.
+
+ \sa toString(), QUuid()
+*/
+QUuid QUuid::fromString(QLatin1String text) Q_DECL_NOTHROW
+{
+ if (Q_UNLIKELY(text.size() < MaxStringUuidLength - 2
+ || (text.front() == QLatin1Char('{') && text.size() < MaxStringUuidLength - 1))) {
+ // Too short. Don't call _q_uuidFromHex(); QL1Ss need not be NUL-terminated,
+ // and we don't want to read trailing garbage as potentially valid data.
+ text = QLatin1String();
}
+ return _q_uuidFromHex(text.data());
}
/*!
\internal
*/
QUuid::QUuid(const char *text)
+ : QUuid(_q_uuidFromHex(text))
{
- if (!text) {
- *this = QUuid();
- return;
- }
-
- if (!_q_uuidFromHex(text, data1, data2, data3, data4)) {
- *this = QUuid();
- return;
- }
}
/*!
Creates a QUuid object from the QByteArray \a text, which must be
formatted as five hex fields separated by '-', e.g.,
- "{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}" where 'x' is a hex
+ "{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}" where each 'x' is a hex
digit. The curly braces shown here are optional, but it is normal to
include them. If the conversion fails, a null UUID is created. See
toByteArray() for an explanation of how the five hex fields map to the
@@ -394,23 +441,8 @@ QUuid::QUuid(const char *text)
\sa toByteArray(), QUuid()
*/
QUuid::QUuid(const QByteArray &text)
+ : QUuid(fromString(QLatin1String(text.data(), text.size())))
{
- if (text.length() < 36) {
- *this = QUuid();
- return;
- }
-
- const char *data = text.constData();
-
- if (*data == '{' && text.length() < 37) {
- *this = QUuid();
- return;
- }
-
- if (!_q_uuidFromHex(data, data1, data2, data3, data4)) {
- *this = QUuid();
- return;
- }
}
/*!
diff --git a/src/corelib/plugin/quuid.h b/src/corelib/plugin/quuid.h
index 264f572993..d975528dcf 100644
--- a/src/corelib/plugin/quuid.h
+++ b/src/corelib/plugin/quuid.h
@@ -116,6 +116,8 @@ public:
#endif
QUuid(const QString &);
+ static QUuid fromString(QStringView string) Q_DECL_NOTHROW;
+ static QUuid fromString(QLatin1String string) Q_DECL_NOTHROW;
QUuid(const char *);
QString toString() const;
QUuid(const QByteArray &);
diff --git a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp
index 0c4f27def2..8a00ed0e40 100644
--- a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp
+++ b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp
@@ -909,7 +909,7 @@ IShellItem *QWindowsNativeFileDialogBase::shellItem(const QUrl &url)
// (see https://msdn.microsoft.com/en-us/library/windows/desktop/dd378457(v=vs.85).aspx)
// specified as "clsid:<GUID>" (without '{', '}').
IShellItem *result = Q_NULLPTR;
- const QUuid uuid(url.path());
+ const auto uuid = QUuid::fromString(url.path());
if (uuid.isNull()) {
qWarning() << __FUNCTION__ << ": Invalid CLSID: " << url.path();
return Q_NULLPTR;
diff --git a/tests/auto/corelib/plugin/quuid/tst_quuid.cpp b/tests/auto/corelib/plugin/quuid/tst_quuid.cpp
index d3102c7ee5..9e3edc96ec 100644
--- a/tests/auto/corelib/plugin/quuid/tst_quuid.cpp
+++ b/tests/auto/corelib/plugin/quuid/tst_quuid.cpp
@@ -41,6 +41,7 @@ private slots:
void fromChar();
void toString();
+ void fromString_data();
void fromString();
void toByteArray();
void fromByteArray();
@@ -127,15 +128,58 @@ void tst_QUuid::toString()
QCOMPARE(uuidB.toString(), QString("{1ab6e93a-b1cb-4a87-ba47-ec7e99039a7b}"));
}
+void tst_QUuid::fromString_data()
+{
+ QTest::addColumn<QUuid>("expected");
+ QTest::addColumn<QString>("input");
+
+ QUuid invalid = {};
+
+#define ROW(which, string) \
+ QTest::addRow("%-38s -> %s", string, #which) << which << string
+ ROW(uuidA, "{fc69b59e-cc34-4436-a43c-ee95d128b8c5}");
+ ROW(uuidA, "fc69b59e-cc34-4436-a43c-ee95d128b8c5}");
+ ROW(uuidA, "{fc69b59e-cc34-4436-a43c-ee95d128b8c5" );
+ ROW(uuidA, "fc69b59e-cc34-4436-a43c-ee95d128b8c5" );
+
+ ROW(uuidA, "{fc69b59e-cc34-4436-a43c-ee95d128b8c56"); // too long (not an error!)
+ ROW(invalid, "{fc69b59e-cc34-4436-a43c-ee95d128b8c" ); // premature end (within length limits)
+ ROW(invalid, " fc69b59e-cc34-4436-a43c-ee95d128b8c5}"); // leading space
+ ROW(uuidA, "{fc69b59e-cc34-4436-a43c-ee95d128b8c5 "); // trailing space (not an error!)
+ ROW(invalid, "{gc69b59e-cc34-4436-a43c-ee95d128b8c5}"); // non-hex digit in 1st group
+ ROW(invalid, "{fc69b59e-cp34-4436-a43c-ee95d128b8c5}"); // non-hex digit in 2nd group
+ ROW(invalid, "{fc69b59e-cc34-44r6-a43c-ee95d128b8c5}"); // non-hex digit in 3rd group
+ ROW(invalid, "{fc69b59e-cc34-4436-a4yc-ee95d128b8c5}"); // non-hex digit in 4th group
+ ROW(invalid, "{fc69b59e-cc34-4436-a43c-ee95d128j8c5}"); // non-hex digit in last group
+ ROW(invalid, "(fc69b59e-cc34-4436-a43c-ee95d128b8c5}"); // wrong initial character
+ ROW(invalid, "{fc69b59e+cc34-4436-a43c-ee95d128b8c5}"); // wrong 1st separator
+ ROW(invalid, "{fc69b59e-cc34*4436-a43c-ee95d128b8c5}"); // wrong 2nd separator
+ ROW(invalid, "{fc69b59e-cc34-44366a43c-ee95d128b8c5}"); // wrong 3rd separator
+ ROW(invalid, "{fc69b59e-cc34-4436-a43c\303\244ee95d128b8c5}"); // wrong 4th separator (&auml;)
+ ROW(uuidA, "{fc69b59e-cc34-4436-a43c-ee95d128b8c5)"); // wrong final character (not an error!)
+
+ ROW(uuidB, "{1ab6e93a-b1cb-4a87-ba47-ec7e99039a7b}");
+#undef ROW
+}
+
void tst_QUuid::fromString()
{
- QCOMPARE(uuidA, QUuid(QString("{fc69b59e-cc34-4436-a43c-ee95d128b8c5}")));
- QCOMPARE(uuidA, QUuid(QString("fc69b59e-cc34-4436-a43c-ee95d128b8c5}")));
- QCOMPARE(uuidA, QUuid(QString("{fc69b59e-cc34-4436-a43c-ee95d128b8c5")));
- QCOMPARE(uuidA, QUuid(QString("fc69b59e-cc34-4436-a43c-ee95d128b8c5")));
- QCOMPARE(QUuid(), QUuid(QString("{fc69b59e-cc34-4436-a43c-ee95d128b8c")));
+ QFETCH(const QUuid, expected);
+ QFETCH(const QString, input);
- QCOMPARE(uuidB, QUuid(QString("{1ab6e93a-b1cb-4a87-ba47-ec7e99039a7b}")));
+ const auto inputL1 = input.toLatin1();
+ const auto inputU8 = input.toUtf8();
+
+ QCOMPARE(expected, QUuid(input));
+ QCOMPARE(expected, QUuid(inputU8));
+ QCOMPARE(expected, QUuid(inputL1));
+
+ QCOMPARE(expected, QUuid::fromString(input));
+
+ // for QLatin1String, construct one whose data() is not NUL-terminated:
+ const auto longerInputL1 = inputL1 + '5'; // the '5' makes the premature end check incorrectly succeed
+ const auto inputL1S = QLatin1String(longerInputL1.data(), inputL1.size());
+ QCOMPARE(expected, QUuid::fromString(inputL1S));
}
void tst_QUuid::toByteArray()
diff --git a/tests/auto/corelib/plugin/quuid/tst_quuid_darwin.mm b/tests/auto/corelib/plugin/quuid/tst_quuid_darwin.mm
index d90bff65b3..41ccece115 100644
--- a/tests/auto/corelib/plugin/quuid/tst_quuid_darwin.mm
+++ b/tests/auto/corelib/plugin/quuid/tst_quuid_darwin.mm
@@ -36,7 +36,7 @@ void tst_QUuid_darwinTypes()
{
// QUuid <-> CFUUID
{
- QUuid qtUuid(QByteArrayLiteral("0f7169cc-5711-4af9-99d9-fecb2329fdef"));
+ const auto qtUuid = QUuid::fromString(QLatin1String("0f7169cc-5711-4af9-99d9-fecb2329fdef"));
const CFUUIDRef cfuuid = qtUuid.toCFUUID();
QCOMPARE(QUuid::fromCFUUID(cfuuid), qtUuid);
CFStringRef cfstring = CFUUIDCreateString(0, cfuuid);
@@ -45,10 +45,10 @@ void tst_QUuid_darwinTypes()
CFRelease(cfuuid);
}
{
- QUuid qtUuid(QByteArrayLiteral("0f7169cc-5711-4af9-99d9-fecb2329fdef"));
+ auto qtUuid = QUuid::fromString(QLatin1String("0f7169cc-5711-4af9-99d9-fecb2329fdef"));
const CFUUIDRef cfuuid = qtUuid.toCFUUID();
QUuid qtUuidCopy(qtUuid);
- qtUuid = QUuid(QByteArrayLiteral("93eec131-13c5-4d13-aaea-e456b4c57efa")); // modify
+ qtUuid = QUuid::fromString(QLatin1String("93eec131-13c5-4d13-aaea-e456b4c57efa")); // modify
QCOMPARE(QUuid::fromCFUUID(cfuuid), qtUuidCopy);
CFStringRef cfstring = CFUUIDCreateString(0, cfuuid);
QCOMPARE(QString::fromCFString(cfstring), qtUuidCopy.toString().mid(1, 36).toUpper());
@@ -59,7 +59,7 @@ void tst_QUuid_darwinTypes()
{
QMacAutoReleasePool pool;
- QUuid qtUuid(QByteArrayLiteral("0f7169cc-5711-4af9-99d9-fecb2329fdef"));
+ const auto qtUuid = QUuid::fromString(QLatin1String("0f7169cc-5711-4af9-99d9-fecb2329fdef"));
const NSUUID *nsuuid = qtUuid.toNSUUID();
QCOMPARE(QUuid::fromNSUUID(nsuuid), qtUuid);
QCOMPARE(QString::fromNSString([nsuuid UUIDString]), qtUuid.toString().mid(1, 36).toUpper());
@@ -67,10 +67,10 @@ void tst_QUuid_darwinTypes()
{
QMacAutoReleasePool pool;
- QUuid qtUuid(QByteArrayLiteral("0f7169cc-5711-4af9-99d9-fecb2329fdef"));
+ auto qtUuid = QUuid::fromString(QLatin1String("0f7169cc-5711-4af9-99d9-fecb2329fdef"));
const NSUUID *nsuuid = qtUuid.toNSUUID();
QUuid qtUuidCopy(qtUuid);
- qtUuid = QUuid(QByteArrayLiteral("93eec131-13c5-4d13-aaea-e456b4c57efa")); // modify
+ qtUuid = QUuid::fromString(QLatin1String("93eec131-13c5-4d13-aaea-e456b4c57efa")); // modify
QCOMPARE(QUuid::fromNSUUID(nsuuid), qtUuidCopy);
QCOMPARE(QString::fromNSString([nsuuid UUIDString]), qtUuidCopy.toString().mid(1, 36).toUpper());
}