From 8045ccc382ac91c14849e10f37d9a8d0605dc562 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Wed, 3 Apr 2019 15:35:30 +0200 Subject: Windows QPA/File dialog: Pass up http[s] URLs The native Windows allows for typing in http[s] URLs directly (without checking existence). Pass these up. Fixes: QTBUG-71785 Change-Id: I60237bab596ca3f52e6f513f17544ff94e9080da Reviewed-by: Andre de la Rocha Reviewed-by: Oliver Wolff --- .../platforms/windows/qwindowsdialoghelpers.cpp | 39 +++++++++++++++------- 1 file changed, 27 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp index ba441a1921..9de3268fc8 100644 --- a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp +++ b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp @@ -1453,26 +1453,41 @@ static QString createTemporaryItemCopy(QWindowsShellItem &qItem, QString *errorM return result; } +static QUrl itemToDialogUrl(QWindowsShellItem &qItem, QString *errorMessage) +{ + QUrl url = qItem.url(); + if (url.isLocalFile() || url.scheme().startsWith(QLatin1String("http"))) + return url; + const QString path = qItem.path(); + if (path.isEmpty() && !qItem.isDir() && qItem.canStream()) { + const QString temporaryCopy = createTemporaryItemCopy(qItem, errorMessage); + if (temporaryCopy.isEmpty()) { + QDebug(errorMessage).noquote() << "Unable to create a local copy of" + << qItem << ": " << errorMessage; + return QUrl(); + } + return QUrl::fromLocalFile(temporaryCopy); + } + if (!url.isValid()) + QDebug(errorMessage).noquote() << "Invalid URL obtained from" << qItem; + return url; +} + QList QWindowsNativeOpenFileDialog::dialogResult() const { QList result; IShellItemArray *items = nullptr; if (SUCCEEDED(openFileDialog()->GetResults(&items)) && items) { + QString errorMessage; for (IShellItem *item : QWindowsShellItem::itemsFromItemArray(items)) { QWindowsShellItem qItem(item); - const QString path = qItem.path(); - if (path.isEmpty() && !qItem.isDir()) { - QString errorMessage; - const QString temporaryCopy = createTemporaryItemCopy(qItem, &errorMessage); - if (temporaryCopy.isEmpty()) { - qWarning().noquote() << "Unable to create a local copy of" << qItem - << ": " << errorMessage; - } else { - result.append(QUrl::fromLocalFile(temporaryCopy)); - } - } else { - result.append(qItem.url()); + const QUrl url = itemToDialogUrl(qItem, &errorMessage); + if (!url.isValid()) { + qWarning("%s", qPrintable(errorMessage)); + result.clear(); + break; } + result.append(url); } } return result; -- cgit v1.2.3 From 3a34ef636af43e249fba417419db14c42b98094a Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Thu, 21 Mar 2019 09:11:27 +0100 Subject: QMenu/QComboBox: Extract helper for determining the pop up geometry MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move the code returning whether a popup should use the full screen to QStylePrivate and use for QMenu and QComboBox. Task-number: QTBUG-73231 Change-Id: I1901ecedfa90edf16329ce3b13ef4abea5ab44e8 Reviewed-by: Morten Johan Sørvig Reviewed-by: Richard Moe Gustavsen --- src/widgets/styles/qstyle.cpp | 8 ++++++++ src/widgets/styles/qstyle_p.h | 3 +++ src/widgets/widgets/qcombobox.cpp | 12 ++++-------- src/widgets/widgets/qmenu.cpp | 30 ++++++++++++++---------------- src/widgets/widgets/qmenu_p.h | 1 + 5 files changed, 30 insertions(+), 24 deletions(-) (limited to 'src') diff --git a/src/widgets/styles/qstyle.cpp b/src/widgets/styles/qstyle.cpp index 97ec1d3f19..ec5b6df6b3 100644 --- a/src/widgets/styles/qstyle.cpp +++ b/src/widgets/styles/qstyle.cpp @@ -46,6 +46,7 @@ #include "qstyleoption.h" #include "private/qstyle_p.h" #include "private/qguiapplication_p.h" +#include #ifndef QT_NO_DEBUG #include "qdebug.h" #endif @@ -2447,6 +2448,13 @@ void QStyle::setProxy(QStyle *style) d->proxyStyle = style; } +//Windows and KDE allow menus to cover the taskbar, while GNOME and macOS don't +bool QStylePrivate::useFullScreenForPopup() +{ + auto theme = QGuiApplicationPrivate::platformTheme(); + return theme && theme->themeHint(QPlatformTheme::UseFullScreenForPopupMenu).toBool(); +} + QT_END_NAMESPACE #include "moc_qstyle.cpp" diff --git a/src/widgets/styles/qstyle_p.h b/src/widgets/styles/qstyle_p.h index 94e4540d0b..9643012c31 100644 --- a/src/widgets/styles/qstyle_p.h +++ b/src/widgets/styles/qstyle_p.h @@ -67,6 +67,9 @@ class QStylePrivate: public QObjectPrivate public: inline QStylePrivate() : layoutSpacingIndex(-1), proxyStyle(0) {} + + static bool useFullScreenForPopup(); + mutable int layoutSpacingIndex; QStyle *proxyStyle; }; diff --git a/src/widgets/widgets/qcombobox.cpp b/src/widgets/widgets/qcombobox.cpp index e20a0892b4..bdd2462c92 100644 --- a/src/widgets/widgets/qcombobox.cpp +++ b/src/widgets/widgets/qcombobox.cpp @@ -80,6 +80,7 @@ #if QT_CONFIG(effects) # include #endif +#include #ifndef QT_NO_ACCESSIBILITY #include "qaccessible.h" #endif @@ -261,16 +262,11 @@ void QComboBoxPrivate::_q_modelDestroyed() model = QAbstractItemModelPrivate::staticEmptyModel(); } - -//Windows and KDE allows menus to cover the taskbar, while GNOME and Mac don't QRect QComboBoxPrivate::popupGeometry(int screen) const { - bool useFullScreenForPopupMenu = false; - if (const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme()) - useFullScreenForPopupMenu = theme->themeHint(QPlatformTheme::UseFullScreenForPopupMenu).toBool(); - return useFullScreenForPopupMenu ? - QDesktopWidgetPrivate::screenGeometry(screen) : - QDesktopWidgetPrivate::availableGeometry(screen); + return QStylePrivate::useFullScreenForPopup() + ? QDesktopWidgetPrivate::screenGeometry(screen) + : QDesktopWidgetPrivate::availableGeometry(screen); } bool QComboBoxPrivate::updateHoverControl(const QPoint &pos) diff --git a/src/widgets/widgets/qmenu.cpp b/src/widgets/widgets/qmenu.cpp index 48253b52b0..a44f0fb8a7 100644 --- a/src/widgets/widgets/qmenu.cpp +++ b/src/widgets/widgets/qmenu.cpp @@ -78,6 +78,7 @@ #include #include #include +#include QT_BEGIN_NAMESPACE @@ -307,29 +308,26 @@ int QMenuPrivate::scrollerHeight() const return qMax(QApplication::globalStrut().height(), q->style()->pixelMetric(QStyle::PM_MenuScrollerHeight, 0, q)); } -//Windows and KDE allow menus to cover the taskbar, while GNOME and Mac don't +// Windows and KDE allow menus to cover the taskbar, while GNOME and macOS +// don't. Torn-off menus are again different +inline bool QMenuPrivate::useFullScreenForPopup() const +{ + return !tornoff && QStylePrivate::useFullScreenForPopup(); +} + QRect QMenuPrivate::popupGeometry() const { Q_Q(const QMenu); - if (!tornoff && // Torn-off menus are different - QGuiApplicationPrivate::platformTheme() && - QGuiApplicationPrivate::platformTheme()->themeHint(QPlatformTheme::UseFullScreenForPopupMenu).toBool()) { - return QDesktopWidgetPrivate::screenGeometry(q); - } else { - return QDesktopWidgetPrivate::availableGeometry(q); - } + return useFullScreenForPopup() + ? QDesktopWidgetPrivate::screenGeometry(q) + : QDesktopWidgetPrivate::availableGeometry(q); } -//Windows and KDE allow menus to cover the taskbar, while GNOME and Mac don't QRect QMenuPrivate::popupGeometry(int screen) const { - if (!tornoff && // Torn-off menus are different - QGuiApplicationPrivate::platformTheme() && - QGuiApplicationPrivate::platformTheme()->themeHint(QPlatformTheme::UseFullScreenForPopupMenu).toBool()) { - return QDesktopWidgetPrivate::screenGeometry(screen); - } else { - return QDesktopWidgetPrivate::availableGeometry(screen); - } + return useFullScreenForPopup() + ? QDesktopWidgetPrivate::screenGeometry(screen) + : QDesktopWidgetPrivate::availableGeometry(screen); } QVector > QMenuPrivate::calcCausedStack() const diff --git a/src/widgets/widgets/qmenu_p.h b/src/widgets/widgets/qmenu_p.h index f740919dc7..d0fa8ff113 100644 --- a/src/widgets/widgets/qmenu_p.h +++ b/src/widgets/widgets/qmenu_p.h @@ -343,6 +343,7 @@ public: void updateActionRects(const QRect &screen) const; QRect popupGeometry() const; QRect popupGeometry(int screen) const; + bool useFullScreenForPopup() const; int getLastVisibleAction() const; //selection -- cgit v1.2.3 From c2a1360b3f0aa33d00882bd6cc4b1990c18e04b8 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Thu, 20 Sep 2018 20:30:46 -0700 Subject: Update TinyCBOR with bugfixes Updated to https://github.com/thiagomacieira/tinycbor commit ac9369d8ec8511bc7516266ae6b07f7da860c954. Fabrice Fontaine (1): fix undefined encode_half in json2cbor Pedro Oliveira (1): Fixed minor error in the example code. Svyatoslav Phirsov (2): Typo fixed in stdlib fread(...) usage typo in dumprecursive return type Thiago Macieira (9): Install the tinycbor-version.h header. Update version number for a possible but unlikely 0.5.3 release Fix #137: off-by-one error in UTF-8 decoding Update Travis CI to Ubuntu Xenial Pretty: fix use of uninitialised variable Validation: fix out-of-bounds access when content ends in a string Parser: apply the same memory-check update Tests: remove useless comment Tests: Catch an earlier QCOMPARE failure in compare() phirsov (6): Fix off-by-one causing buffer overflow in open_memstream Protect macro argument expansion using parentheses eliminating misleading messages in case .config file not yet created Run check silently in Travis Make AppVeyor test suit run silent as in Travis enhancement #149 implemented: access half-precision floating point data as single float Change-Id: I9e3d261ad9bf41cfb2b6fffd159088f1cc9b3b02 Reviewed-by: Edward Welbourne --- src/3rdparty/tinycbor/src/cbor.h | 4 +- src/3rdparty/tinycbor/src/cborencoder.c | 24 +- src/3rdparty/tinycbor/src/cborparser.c | 2 +- src/3rdparty/tinycbor/src/compilersupport_p.h | 2 +- src/3rdparty/tinycbor/tests/encoder/data.cpp | 36 ++ .../tinycbor/tests/encoder/tst_encoder.cpp | 125 ++++++- src/3rdparty/tinycbor/tests/parser/tst_parser.cpp | 377 +++++++++++++++------ src/corelib/serialization/qcborstream.cpp | 10 + 8 files changed, 467 insertions(+), 113 deletions(-) (limited to 'src') diff --git a/src/3rdparty/tinycbor/src/cbor.h b/src/3rdparty/tinycbor/src/cbor.h index 5c7ba74e39..3672bd0d98 100644 --- a/src/3rdparty/tinycbor/src/cbor.h +++ b/src/3rdparty/tinycbor/src/cbor.h @@ -257,6 +257,7 @@ CBOR_INLINE_API CborError cbor_encode_undefined(CborEncoder *encoder) CBOR_INLINE_API CborError cbor_encode_half_float(CborEncoder *encoder, const void *value) { return cbor_encode_floating_point(encoder, CborHalfFloatType, value); } +CBOR_API CborError cbor_encode_float_as_half_float(CborEncoder *encoder, float value); CBOR_INLINE_API CborError cbor_encode_float(CborEncoder *encoder, float value) { return cbor_encode_floating_point(encoder, CborFloatType, &value); } CBOR_INLINE_API CborError cbor_encode_double(CborEncoder *encoder, double value) @@ -593,12 +594,13 @@ CBOR_API CborError cbor_value_map_find_value(const CborValue *map, const char *s /* Floating point */ CBOR_INLINE_API bool cbor_value_is_half_float(const CborValue *value) { return value->type == CborHalfFloatType; } +CBOR_API CborError cbor_value_get_half_float_as_float(const CborValue *value, float *result); CBOR_INLINE_API CborError cbor_value_get_half_float(const CborValue *value, void *result) { assert(cbor_value_is_half_float(value)); assert((value->flags & CborIteratorFlag_IntegerValueTooLarge) == 0); - /* size has been computed already */ + /* size has already been computed */ memcpy(result, &value->extra, sizeof(value->extra)); return CborNoError; } diff --git a/src/3rdparty/tinycbor/src/cborencoder.c b/src/3rdparty/tinycbor/src/cborencoder.c index 52a4025be1..38804cfa6f 100644 --- a/src/3rdparty/tinycbor/src/cborencoder.c +++ b/src/3rdparty/tinycbor/src/cborencoder.c @@ -76,7 +76,7 @@ * \code * uint8_t buf[16]; * CborEncoder encoder, mapEncoder; - * cbor_encoder_init(&encoder, &buf, sizeof(buf), 0); + * cbor_encoder_init(&encoder, buf, sizeof(buf), 0); * cbor_encoder_create_map(&encoder, &mapEncoder, 1); * cbor_encode_text_stringz(&mapEncoder, "foo"); * cbor_encode_boolean(&mapEncoder, some_value); @@ -115,7 +115,7 @@ * uint8_t buf[16]; * CborError err; * CborEncoder encoder, mapEncoder; - * cbor_encoder_init(&encoder, &buf, sizeof(buf), 0); + * cbor_encoder_init(&encoder, buf, sizeof(buf), 0); * err = cbor_encoder_create_map(&encoder, &mapEncoder, 1); * if (!err) * return err; @@ -155,7 +155,7 @@ * goto error; * buf = nbuf; * - * cbor_encoder_init(&encoder, &buf, size, 0); + * cbor_encoder_init(&encoder, buf, size, 0); * err = cbor_encoder_create_array(&encoder, &arrayEncoder, n); * cbor_assert(err); // can't fail, the buffer is always big enough * @@ -411,7 +411,7 @@ CborError cbor_encode_simple_value(CborEncoder *encoder, uint8_t value) * This function is useful for code that needs to pass through floating point * values but does not wish to have the actual floating-point code. * - * \sa cbor_encode_half_float, cbor_encode_float, cbor_encode_double + * \sa cbor_encode_half_float, cbor_encode_float_as_half_float, cbor_encode_float, cbor_encode_double */ CborError cbor_encode_floating_point(CborEncoder *encoder, CborType fpType, const void *value) { @@ -621,13 +621,25 @@ CborError cbor_encoder_close_container(CborEncoder *encoder, const CborEncoder * * \sa cbor_encode_floating_point(), cbor_encode_float(), cbor_encode_double() */ +/** + * \fn CborError cbor_encode_float_as_half_float(CborEncoder *encoder, float value) + * + * Convert the IEEE 754 single-precision (32-bit) floating point value \a value + * to the IEEE 754 half-precision (16-bit) floating point value and append it + * to the CBOR stream provided by \a encoder. + * The \a value should be in the range of the IEEE 754 half-precision floating point type, + * INFINITY, -INFINITY, or NAN, otherwise the behavior of this function is undefined. + * + * \sa cbor_encode_floating_point(), cbor_encode_float(), cbor_encode_double() + */ + /** * \fn CborError cbor_encode_float(CborEncoder *encoder, float value) * * Appends the IEEE 754 single-precision (32-bit) floating point value \a value * to the CBOR stream provided by \a encoder. * - * \sa cbor_encode_floating_point(), cbor_encode_half_float(), cbor_encode_double() + * \sa cbor_encode_floating_point(), cbor_encode_half_float(), cbor_encode_float_as_half_float(), cbor_encode_double() */ /** @@ -636,7 +648,7 @@ CborError cbor_encoder_close_container(CborEncoder *encoder, const CborEncoder * * Appends the IEEE 754 double-precision (64-bit) floating point value \a value * to the CBOR stream provided by \a encoder. * - * \sa cbor_encode_floating_point(), cbor_encode_half_float(), cbor_encode_float() + * \sa cbor_encode_floating_point(), cbor_encode_half_float(), cbor_encode_float_as_half_float(), cbor_encode_float() */ /** diff --git a/src/3rdparty/tinycbor/src/cborparser.c b/src/3rdparty/tinycbor/src/cborparser.c index 971230ea61..90a7d2ced6 100644 --- a/src/3rdparty/tinycbor/src/cborparser.c +++ b/src/3rdparty/tinycbor/src/cborparser.c @@ -1520,7 +1520,7 @@ error: * floating point, this function takes a \c{void *} as a parameter for the * storage area, which must be at least 16 bits wide. * - * \sa cbor_value_get_type(), cbor_value_is_valid(), cbor_value_is_half_float(), cbor_value_get_float() + * \sa cbor_value_get_type(), cbor_value_is_valid(), cbor_value_is_half_float(), cbor_value_get_half_float_as_float(), cbor_value_get_float() */ /** @} */ diff --git a/src/3rdparty/tinycbor/src/compilersupport_p.h b/src/3rdparty/tinycbor/src/compilersupport_p.h index 2b9491d34d..bd10efc9c7 100644 --- a/src/3rdparty/tinycbor/src/compilersupport_p.h +++ b/src/3rdparty/tinycbor/src/compilersupport_p.h @@ -106,7 +106,7 @@ # define cbor_ntohs __builtin_bswap16 # define cbor_htons __builtin_bswap16 # else -# define cbor_ntohs(x) (((uint16_t)x >> 8) | ((uint16_t)x << 8)) +# define cbor_ntohs(x) (((uint16_t)(x) >> 8) | ((uint16_t)(x) << 8)) # define cbor_htons cbor_ntohs # endif # else diff --git a/src/3rdparty/tinycbor/tests/encoder/data.cpp b/src/3rdparty/tinycbor/tests/encoder/data.cpp index c33fb605aa..8b00cfec1f 100644 --- a/src/3rdparty/tinycbor/tests/encoder/data.cpp +++ b/src/3rdparty/tinycbor/tests/encoder/data.cpp @@ -123,6 +123,42 @@ QVariant make_ilmap(const std::initializer_list> &list return QVariant::fromValue(IndeterminateLengthMap(list)); } +void addHalfFloat() +{ + QTest::addColumn("output"); + QTest::addColumn("rawInput"); + QTest::addColumn("floatInput"); + + QTest::newRow("+0") << raw("\x00\x00") << 0U << 0.0; + QTest::newRow("-0") << raw("\x80\x00") << 0x8000U << 0.0; + + QTest::newRow("min.denorm") << raw("\x00\x01") << 1U << ldexp(1.0, -14) * ldexp(1.0, -10); + QTest::newRow("-min.denorm") << raw("\x80\x01") << 0x8001U << ldexp(-1.0, -14) * ldexp(1.0, -10); + + QTest::newRow("max.denorm") << raw("\x03\xff") << 0x03ffU << ldexp(1.0, -14) * (1.0 - ldexp(1.0, -10)); + QTest::newRow("-max.denorm") << raw("\x83\xff") << 0x83ffU << ldexp(-1.0, -14) * (1.0 - ldexp(1.0, -10)); + + QTest::newRow("min.norm") << raw("\x04\x00") << 0x0400U << ldexp(1.0, -14); + QTest::newRow("-min.norm") << raw("\x84\x00") << 0x8400U << ldexp(-1.0, -14); + + QTest::newRow("1.0") << raw("\x3c\x00") << 0x3c00U << 1.0; + QTest::newRow("-1.0") << raw("\xbc\x00") << 0xbc00U << -1.0; + + QTest::newRow("1.5") << raw("\x3e\x00") << 0x3e00U << 1.5; + QTest::newRow("-1.5") << raw("\xbe\x00") << 0xbe00U << -1.5; + + QTest::newRow("max") << raw("\x7b\xff") << 0x7bffU << ldexp(1.0, 15) * (2.0 - ldexp(1.0, -10)); + QTest::newRow("-max") << raw("\xfb\xff") << 0xfbffU << ldexp(-1.0, 15) * (2.0 - ldexp(1.0, -10)); + + QTest::newRow("inf") << raw("\x7c\x00") << 0x7c00U << myInf(); + QTest::newRow("-inf") << raw("\xfc\x00") << 0xfc00U << myNInf(); + + QTest::newRow("nan1") << raw("\x7c\x01") << 0x7c01U << myNaN(); + QTest::newRow("nan2") << raw("\xfc\x01") << 0xfc01U << myNaN(); + QTest::newRow("nan3") << raw("\x7e\x00") << 0x7e00U << myNaN(); + QTest::newRow("nan4") << raw("\xfe\x00") << 0xfe00U << myNaN(); +} + void addColumns() { QTest::addColumn("output"); diff --git a/src/3rdparty/tinycbor/tests/encoder/tst_encoder.cpp b/src/3rdparty/tinycbor/tests/encoder/tst_encoder.cpp index f30c522601..458f55eb10 100644 --- a/src/3rdparty/tinycbor/tests/encoder/tst_encoder.cpp +++ b/src/3rdparty/tinycbor/tests/encoder/tst_encoder.cpp @@ -41,6 +41,13 @@ class tst_Encoder : public QObject { Q_OBJECT private slots: + void floatAsHalfFloat_data(); + void floatAsHalfFloat(); + void halfFloat_data(); + void halfFloat(); + void floatAsHalfFloatCloseToZero_data(); + void floatAsHalfFloatCloseToZero(); + void floatAsHalfFloatNaN(); void fixed_data(); void fixed(); void strings_data(); @@ -178,21 +185,127 @@ CborError encodeVariant(CborEncoder *encoder, const QVariant &v) return CborErrorUnknownType; } -void compare(const QVariant &input, const QByteArray &output) +template +void encodeOne(Input input, FnUnderTest fn_under_test, QByteArray &buffer, CborError &error) { - QByteArray buffer(output.length(), Qt::Uninitialized); uint8_t *bufptr = reinterpret_cast(buffer.data()); CborEncoder encoder; cbor_encoder_init(&encoder, bufptr, buffer.length(), 0); - QCOMPARE(encodeVariant(&encoder, input), CborNoError); - QCOMPARE(encoder.remaining, size_t(1)); - QCOMPARE(cbor_encoder_get_extra_bytes_needed(&encoder), size_t(0)); + error = fn_under_test(&encoder, input); + + if (error == CborNoError) { + QCOMPARE(encoder.remaining, size_t(1)); + QCOMPARE(cbor_encoder_get_extra_bytes_needed(&encoder), size_t(0)); + + buffer.resize(int(cbor_encoder_get_buffer_size(&encoder, bufptr))); + } +} - buffer.resize(int(cbor_encoder_get_buffer_size(&encoder, bufptr))); +template +void compare(Input input, FnUnderTest fn_under_test, const QByteArray &output) +{ + QByteArray buffer(output.length(), Qt::Uninitialized); + CborError error; + + encodeOne(input, fn_under_test, buffer, error); + if (QTest::currentTestFailed()) + return; + + QCOMPARE(error, CborNoError); QCOMPARE(buffer, output); } +void compare(const QVariant &input, const QByteArray &output) +{ + compare(input, encodeVariant, output); +} + +void tst_Encoder::floatAsHalfFloat_data() +{ + addHalfFloat(); +} + +void tst_Encoder::floatAsHalfFloat() +{ + QFETCH(unsigned, rawInput); + QFETCH(double, floatInput); + QFETCH(QByteArray, output); + + if (rawInput == 0U || rawInput == 0x8000U) + QSKIP("zero values are out of scope of this test case", QTest::SkipSingle); + + if (qIsNaN(floatInput)) + QSKIP("NaN values are out of scope of this test case", QTest::SkipSingle); + + output.prepend('\xf9'); + + compare((float)floatInput, cbor_encode_float_as_half_float, output); +} + +void tst_Encoder::halfFloat_data() +{ + addHalfFloat(); +} + +void tst_Encoder::halfFloat() +{ + QFETCH(unsigned, rawInput); + QFETCH(QByteArray, output); + + uint16_t v = (uint16_t)rawInput; + output.prepend('\xf9'); + + compare(&v, cbor_encode_half_float, output); +} + +void tst_Encoder::floatAsHalfFloatCloseToZero_data() +{ + QTest::addColumn("floatInput"); + + QTest::newRow("+0") << 0.0; + QTest::newRow("-0") << -0.0; + + QTest::newRow("below min.denorm") << ldexp(1.0, -14) * ldexp(1.0, -11); + QTest::newRow("above -min.denorm") << ldexp(-1.0, -14) * ldexp(1.0, -11); +} + +void tst_Encoder::floatAsHalfFloatCloseToZero() +{ + QFETCH(double, floatInput); + + QByteArray buffer(4, Qt::Uninitialized); + CborError error; + + encodeOne((float)floatInput, cbor_encode_float_as_half_float, buffer, error); + + QCOMPARE(error, CborNoError); + + QVERIFY2( + buffer == raw("\xf9\x00\x00") || buffer == raw("\xf9\x80\x00"), + "Got value " + QByteArray::number(floatInput) + " encoded to: " + buffer); +} + +void tst_Encoder::floatAsHalfFloatNaN() +{ + QByteArray buffer(4, Qt::Uninitialized); + CborError error; + + encodeOne(myNaNf(), cbor_encode_float_as_half_float, buffer, error); + + QCOMPARE(error, CborNoError); + QCOMPARE(buffer.size(), 3); + + uint8_t ini_byte = (uint8_t)buffer[0], + exp = (uint8_t)buffer[1] & 0x7cU, + manth = (uint8_t)buffer[1] & 0x03U, + mantl = (uint8_t)buffer[2]; + + QCOMPARE((unsigned)ini_byte, 0xf9U); + QCOMPARE((unsigned)exp, 0x7cU); + QVERIFY((manth | mantl) != 0); +} + void tst_Encoder::fixed_data() { addColumns(); diff --git a/src/3rdparty/tinycbor/tests/parser/tst_parser.cpp b/src/3rdparty/tinycbor/tests/parser/tst_parser.cpp index 74c480bc51..2b10004faa 100644 --- a/src/3rdparty/tinycbor/tests/parser/tst_parser.cpp +++ b/src/3rdparty/tinycbor/tests/parser/tst_parser.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2017 Intel Corporation +** Copyright (C) 2019 Intel Corporation ** ** Permission is hereby granted, free of charge, to any person obtaining a copy ** of this software and associated documentation files (the "Software"), to deal @@ -23,11 +23,22 @@ ****************************************************************************/ #define _XOPEN_SOURCE 700 +#define _DARWIN_C_SOURCE 1 /* need MAP_ANON */ #include #include "cbor.h" #include #include +#if defined(Q_OS_UNIX) +# include +# include +#elif defined(Q_OS_WIN) +# define WIN32_LEAN_AND_MEAN 1 +# define NOMINMAX 1 +# include +#endif + + namespace QTest { template<> char *toString(const CborError &err) { @@ -44,6 +55,8 @@ private slots: // parsing API void integers_data(); void integers(); + void halfFloat_data(); + void halfFloat(); void fixed_data(); void fixed(); void strings_data(); @@ -105,6 +118,100 @@ private slots: void recursionLimit(); }; +struct ParserWrapper +{ + void *realdata = nullptr; + uint8_t *data; + size_t len; + CborParser parser; + CborValue first; + + ~ParserWrapper() { freeMemory(); } + + CborError init(const QByteArray &ba, uint32_t flags = 0) + { + return init(ba.constData(), ba.size(), flags); + } + CborError init(const char *ptr, int n, uint32_t flags = 0) + { + freeMemory(); + data = allocateMemory(n); + memcpy(data, ptr, len); + return cbor_parser_init(data, len, flags, &parser, &first); + } + uint8_t *begin() { return data; } + uint8_t *end() { return data + len; } + + uint8_t *allocateMemory(size_t); + void freeMemory(); + + static const size_t PageSize = 4096; + static inline size_t mmapAllocation(size_t n) + { + // round up and add one page + return (n + 2*PageSize) & ~(PageSize - 1); + } + static bool shouldUseMmap(); +}; + +bool ParserWrapper::shouldUseMmap() +{ + static int v = qEnvironmentVariableIntValue("PARSER_NO_MMAP"); + return !v; +} + +uint8_t *ParserWrapper::allocateMemory(size_t n) +{ + len = n; + if (shouldUseMmap()) { + size_t alloc = mmapAllocation(n); +#if defined(Q_OS_UNIX) + realdata = mmap(nullptr, alloc, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); + Q_ASSERT_X(realdata != MAP_FAILED, "allocateMemory", "mmap failed!"); + + // mark last page inaccessible + uint8_t *ptr = static_cast(realdata); + ptr += alloc - PageSize; + mprotect(ptr, PageSize, PROT_NONE); + + ptr -= n; + return ptr; +#elif defined(Q_OS_WIN) + DWORD flAllocationType = MEM_COMMIT | MEM_RESERVE; + DWORD flProtect = PAGE_READWRITE; + realdata = VirtualAlloc(nullptr, alloc, flAllocationType, flProtect); + Q_ASSERT_X(realdata, "allocateMemory", "VirtualAlloc failed!"); + + // mark last page inaccessible + uint8_t *ptr = static_cast(realdata); + ptr += alloc - PageSize; + VirtualProtect(ptr, PageSize, PAGE_NOACCESS, nullptr); + + ptr -= n; + return ptr; +#endif + } + realdata = malloc(n); + return static_cast(realdata); +} + +void ParserWrapper::freeMemory() +{ + if (shouldUseMmap()) { + if (realdata) { +#if defined(Q_OS_UNIX) + size_t alloc = mmapAllocation(len); + munmap(realdata, alloc); +#elif defined(Q_OS_WIN) + VirtualFree(realdata, 0, MEM_RELEASE); +#endif + } + return; + } + + free(realdata); +} + static CborError qstring_printf(void *out, const char *fmt, ...) { auto str = static_cast(out); @@ -166,47 +273,46 @@ bool compareFailed = true; void compareOne_real(const QByteArray &data, const QString &expected, int line, int n = -1) { compareFailed = true; - CborParser parser; - CborValue first; - CborError err = cbor_parser_init(reinterpret_cast(data.constData()), data.length(), 0, &parser, &first); + ParserWrapper w; + CborError err = w.init(data); QVERIFY2(!err, QByteArray::number(line) + ": Got error \"" + cbor_error_string(err) + "\""); - if (cbor_value_get_type(&first) == CborArrayType) { + if (cbor_value_get_type(&w.first) == CborArrayType) { size_t len; if (n >= 0) { - QVERIFY(cbor_value_is_length_known(&first)); - QCOMPARE(cbor_value_get_array_length(&first, &len), CborNoError); + QVERIFY(cbor_value_is_length_known(&w.first)); + QCOMPARE(cbor_value_get_array_length(&w.first, &len), CborNoError); QCOMPARE(len, size_t(len)); } else { - QVERIFY(!cbor_value_is_length_known(&first)); - QCOMPARE(cbor_value_get_array_length(&first, &len), CborErrorUnknownLength); + QVERIFY(!cbor_value_is_length_known(&w.first)); + QCOMPARE(cbor_value_get_array_length(&w.first, &len), CborErrorUnknownLength); } - } else if (cbor_value_get_type(&first) == CborMapType) { + } else if (cbor_value_get_type(&w.first) == CborMapType) { size_t len; if (n >= 0) { - QVERIFY(cbor_value_is_length_known(&first)); - QCOMPARE(cbor_value_get_map_length(&first, &len), CborNoError); + QVERIFY(cbor_value_is_length_known(&w.first)); + QCOMPARE(cbor_value_get_map_length(&w.first, &len), CborNoError); QCOMPARE(len, size_t(len)); } else { - QVERIFY(!cbor_value_is_length_known(&first)); - QCOMPARE(cbor_value_get_map_length(&first, &len), CborErrorUnknownLength); + QVERIFY(!cbor_value_is_length_known(&w.first)); + QCOMPARE(cbor_value_get_map_length(&w.first, &len), CborErrorUnknownLength); } - } else if (cbor_value_is_text_string(&first) || cbor_value_is_byte_string(&first)) { + } else if (cbor_value_is_text_string(&w.first) || cbor_value_is_byte_string(&w.first)) { size_t len; - QCOMPARE(cbor_value_calculate_string_length(&first, &len), CborNoError); - if (cbor_value_is_length_known(&first)) { + QCOMPARE(cbor_value_calculate_string_length(&w.first, &len), CborNoError); + if (cbor_value_is_length_known(&w.first)) { size_t len2; - QCOMPARE(cbor_value_get_string_length(&first, &len2), CborNoError); + QCOMPARE(cbor_value_get_string_length(&w.first, &len2), CborNoError); QCOMPARE(len2, len); } else { - QCOMPARE(cbor_value_get_string_length(&first, &len), CborErrorUnknownLength); + QCOMPARE(cbor_value_get_string_length(&w.first, &len), CborErrorUnknownLength); } } - CborError err2 = cbor_value_validate_basic(&first); + CborError err2 = cbor_value_validate_basic(&w.first); QString decoded; - err = parseOne(&first, &decoded); + err = parseOne(&w.first, &decoded); QVERIFY2(!err, QByteArray::number(line) + ": Got error \"" + cbor_error_string(err) + "\"; decoded stream:\n" + decoded.toLatin1()); QCOMPARE(decoded, expected); @@ -215,7 +321,7 @@ void compareOne_real(const QByteArray &data, const QString &expected, int line, QCOMPARE(err2, err); // check that we consumed everything - QCOMPARE((void*)cbor_value_get_next_byte(&first), (void*)data.constEnd()); + QCOMPARE((void*)cbor_value_get_next_byte(&w.first), (void*)w.end()); compareFailed = false; } @@ -237,39 +343,112 @@ void tst_Parser::integers() QFETCH(qint64, expectedValue); QFETCH(bool, inInt64Range); - CborParser parser; - CborValue first; - CborError err = cbor_parser_init(reinterpret_cast(data.constData()), data.length(), 0, &parser, &first); + ParserWrapper w; + CborError err = w.init(data); QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\""); - QVERIFY(cbor_value_is_integer(&first)); + QVERIFY(cbor_value_is_integer(&w.first)); uint64_t raw; - cbor_value_get_raw_integer(&first, &raw); + cbor_value_get_raw_integer(&w.first, &raw); QCOMPARE(quint64(raw), expectedRaw); if (isNegative) { - QVERIFY(cbor_value_is_negative_integer(&first)); - QVERIFY(!cbor_value_is_unsigned_integer(&first)); + QVERIFY(cbor_value_is_negative_integer(&w.first)); + QVERIFY(!cbor_value_is_unsigned_integer(&w.first)); } else { - QVERIFY(!cbor_value_is_negative_integer(&first)); - QVERIFY(cbor_value_is_unsigned_integer(&first)); + QVERIFY(!cbor_value_is_negative_integer(&w.first)); + QVERIFY(cbor_value_is_unsigned_integer(&w.first)); } int64_t value; if (inInt64Range) { - cbor_value_get_int64(&first, &value); + cbor_value_get_int64(&w.first, &value); QCOMPARE(qint64(value), expectedValue); } - err = cbor_value_get_int64_checked(&first, &value); + err = cbor_value_get_int64_checked(&w.first, &value); QCOMPARE(err, inInt64Range ? CborNoError : CborErrorDataTooLarge); int ivalue; bool inIntRange = inInt64Range && (expectedValue == int(expectedValue)); - err = cbor_value_get_int_checked(&first, &ivalue); + err = cbor_value_get_int_checked(&w.first, &ivalue); QCOMPARE(err, inIntRange ? CborNoError : CborErrorDataTooLarge); } +static void addHalfFloat() +{ + QTest::addColumn("data"); + QTest::addColumn("expectedRaw"); + QTest::addColumn("expectedValue"); + + QTest::newRow("+0") << raw("\x00\x00") << 0U << 0.0; + QTest::newRow("-0") << raw("\x80\x00") << 0x8000U << 0.0; + + QTest::newRow("min.denorm") << raw("\x00\x01") << 1U << ldexp(1.0, -14) * ldexp(1.0, -10); + QTest::newRow("-min.denorm") << raw("\x80\x01") << 0x8001U << ldexp(-1.0, -14) * ldexp(1.0, -10); + + QTest::newRow("max.denorm") << raw("\x03\xff") << 0x03ffU << ldexp(1.0, -14) * (1.0 - ldexp(1.0, -10)); + QTest::newRow("-max.denorm") << raw("\x83\xff") << 0x83ffU << ldexp(-1.0, -14) * (1.0 - ldexp(1.0, -10)); + + QTest::newRow("min.norm") << raw("\x04\x00") << 0x0400U << ldexp(1.0, -14); + QTest::newRow("-min.norm") << raw("\x84\x00") << 0x8400U << ldexp(-1.0, -14); + + QTest::newRow("1.0") << raw("\x3c\x00") << 0x3c00U << 1.0; + QTest::newRow("-1.0") << raw("\xbc\x00") << 0xbc00U << -1.0; + + QTest::newRow("1.5") << raw("\x3e\x00") << 0x3e00U << 1.5; + QTest::newRow("-1.5") << raw("\xbe\x00") << 0xbe00U << -1.5; + + QTest::newRow("max") << raw("\x7b\xff") << 0x7bffU << ldexp(1.0, 15) * (2.0 - ldexp(1.0, -10)); + QTest::newRow("-max") << raw("\xfb\xff") << 0xfbffU << ldexp(-1.0, 15) * (2.0 - ldexp(1.0, -10)); + + QTest::newRow("inf") << raw("\x7c\x00") << 0x7c00U << double(INFINITY); + QTest::newRow("-inf") << raw("\xfc\x00") << 0xfc00U << double(-INFINITY); + + QTest::newRow("nan") << raw("\x7c\x01") << 0x7c01U << double(NAN); + QTest::newRow("nan2") << raw("\xfc\x01") << 0xfc01U << double(NAN); + QTest::newRow("nan3") << raw("\x7e\x00") << 0x7e00U << double(NAN); + QTest::newRow("nan4") << raw("\xfe\x00") << 0xfe00U << double(NAN); +} + +void tst_Parser::halfFloat_data() +{ + addHalfFloat(); +} + +void tst_Parser::halfFloat() +{ + QFETCH(QByteArray, data); + QFETCH(unsigned, expectedRaw); + QFETCH(double, expectedValue); + + CborParser parser; + CborValue first; + + data.prepend('\xf9'); + + CborError err = cbor_parser_init(reinterpret_cast(data.constData()), data.length(), 0, &parser, &first); + QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\""); + QVERIFY(cbor_value_is_half_float(&first)); + + uint16_t raw; + cbor_value_get_half_float(&first, &raw); + QCOMPARE(raw, uint16_t(expectedRaw)); + + float value; + cbor_value_get_half_float_as_float(&first, &value); + + const double epsilon = ldexp(1.0, -25); + + if (qIsNaN(expectedValue)) { + QVERIFY(qIsNaN(value)); + } else if (qIsInf(expectedValue)) { + QVERIFY(value == (float)expectedValue); + } else { + QVERIFY(qAbs(value - (float)expectedValue) < epsilon); + } +} + void tst_Parser::fixed_data() { addColumns(); @@ -678,14 +857,13 @@ void tst_Parser::chunkedString_data() static void chunkedStringTest(const QByteArray &data, const QString &concatenated, QStringList &chunks, CborType ourType) { - CborParser parser; - CborValue first; - CborError err = cbor_parser_init(reinterpret_cast(data.constData()), data.length(), 0, &parser, &first); + ParserWrapper w; + CborError err = w.init(data); QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\""); CborValue value; - QVERIFY(cbor_value_is_array(&first)); - err = cbor_value_enter_container(&first, &value); + QVERIFY(cbor_value_is_array(&w.first)); + err = cbor_value_enter_container(&w.first, &value); QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\""); QVERIFY(cbor_value_is_byte_string(&value) || cbor_value_is_text_string(&value)); @@ -748,9 +926,9 @@ static void chunkedStringTest(const QByteArray &data, const QString &concatenate // confirm EOF QVERIFY(cbor_value_at_end(&value)); - err = cbor_value_leave_container(&first, &value); + err = cbor_value_leave_container(&w.first, &value); QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\""); - QCOMPARE((void*)cbor_value_get_next_byte(&first), (void*)data.constEnd()); + QCOMPARE((void*)cbor_value_get_next_byte(&w.first), (void*)w.end()); } void tst_Parser::chunkedString() @@ -840,18 +1018,17 @@ void tst_Parser::stringLength() QFETCH(QByteArray, data); QFETCH(int, expected); - CborParser parser; - CborValue value; - CborError err = cbor_parser_init(reinterpret_cast(data.constData()), data.length(), 0, &parser, &value); + ParserWrapper w; + CborError err = w.init(data); QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\""); size_t result; - err = cbor_value_calculate_string_length(&value, &result); + err = cbor_value_calculate_string_length(&w.first, &result); QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\""); QCOMPARE(result, size_t(expected)); - if (cbor_value_is_length_known(&value)) { - QCOMPARE(cbor_value_get_string_length(&value, &result), CborNoError); + if (cbor_value_is_length_known(&w.first)) { + QCOMPARE(cbor_value_get_string_length(&w.first, &result), CborNoError); QCOMPARE(result, size_t(expected)); } @@ -935,25 +1112,24 @@ void compareOneString(const QByteArray &data, const QString &string, bool expect { compareFailed = true; - CborParser parser; - CborValue value; - CborError err = cbor_parser_init(reinterpret_cast(data.constData()), data.length(), 0, &parser, &value); + ParserWrapper w; + CborError err = w.init(data); QVERIFY2(!err, QByteArray::number(line) + ": Got error \"" + cbor_error_string(err) + "\""); bool result; QByteArray bastring = string.toUtf8(); - err = cbor_value_text_string_equals(&value, bastring.constData(), &result); + err = cbor_value_text_string_equals(&w.first, bastring.constData(), &result); QVERIFY2(!err, QByteArray::number(line) + ": Got error \"" + cbor_error_string(err) + "\""); QCOMPARE(result, expected); if (expected) { size_t len; - cbor_value_skip_tag(&value); - if (cbor_value_is_length_known(&value)) { - QCOMPARE(cbor_value_get_string_length(&value, &len), CborNoError); + cbor_value_skip_tag(&w.first); + if (cbor_value_is_length_known(&w.first)) { + QCOMPARE(cbor_value_get_string_length(&w.first, &len), CborNoError); QCOMPARE(int(len), bastring.size()); } - QCOMPARE(cbor_value_calculate_string_length(&value, &len), CborNoError); + QCOMPARE(cbor_value_calculate_string_length(&w.first, &len), CborNoError); QCOMPARE(int(len), bastring.size()); } @@ -1042,13 +1218,12 @@ void tst_Parser::mapFind() QFETCH(QByteArray, data); QFETCH(bool, expected); - CborParser parser; - CborValue value; - CborError err = cbor_parser_init(reinterpret_cast(data.constData()), data.length(), 0, &parser, &value); + ParserWrapper w; + CborError err = w.init(data); QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\""); CborValue element; - err = cbor_value_map_find_value(&value, "needle", &element); + err = cbor_value_map_find_value(&w.first, "needle", &element); QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\""); if (expected) { @@ -1119,13 +1294,12 @@ void tst_Parser::checkedIntegers() QFETCH(QVariant, result); int64_t expected = result.toLongLong(); - CborParser parser; - CborValue value; - CborError err = cbor_parser_init(reinterpret_cast(data.constData()), data.length(), 0, &parser, &value); + ParserWrapper w; + CborError err = w.init(data); QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\""); int64_t v; - err = cbor_value_get_int64_checked(&value, &v); + err = cbor_value_get_int64_checked(&w.first, &v); if (result.isNull()) { QCOMPARE(err, CborErrorDataTooLarge); } else { @@ -1133,7 +1307,7 @@ void tst_Parser::checkedIntegers() } int v2; - err = cbor_value_get_int_checked(&value, &v2); + err = cbor_value_get_int_checked(&w.first, &v2); if (result.isNull() || expected < std::numeric_limits::min() || expected > std::numeric_limits::max()) { QCOMPARE(err, CborErrorDataTooLarge); } else { @@ -1154,14 +1328,13 @@ void tst_Parser::validation() QFETCH(CborError, expectedError); QString decoded; - CborParser parser; - CborValue first; - CborError err = cbor_parser_init(reinterpret_cast(data.constData()), data.length(), flags, &parser, &first); + ParserWrapper w; + CborError err = w.init(data, uint32_t(flags)); QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\""); - CborError err2 = cbor_value_validate_basic(&first); - CborError err3 = cbor_value_validate(&first, CborValidateBasic); - err = parseOne(&first, &decoded); + CborError err2 = cbor_value_validate_basic(&w.first); + CborError err3 = cbor_value_validate(&w.first, CborValidateBasic); + err = parseOne(&w.first, &decoded); QCOMPARE(err, expectedError); if (!QByteArray(QTest::currentDataTag()).contains("utf8")) { QCOMPARE(err2, expectedError); @@ -1352,24 +1525,36 @@ void tst_Parser::strictValidation_data() QTest::newRow("overlong-_stringx2-0*8") << raw("\x7f\x60\x7b\0\0\0\0\0\0\0\0\xff") << int(CborValidateShortestNumbers) << CborErrorOverlongEncoding; // strict mode - QTest::newRow("invalid-utf8-1char") << raw("\x61\x80") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString; - QTest::newRow("invalid-utf8-2chars-1") << raw("\x62\xc2\xc0") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString; - QTest::newRow("invalid-utf8-2chars-2") << raw("\x62\xc3\xdf") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString; - QTest::newRow("invalid-utf8-2chars-3") << raw("\x62\xc7\xf0") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString; - QTest::newRow("invalid-utf8-3chars-1") << raw("\x63\xe0\xa0\xc0") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString; - QTest::newRow("invalid-utf8-3chars-2") << raw("\x63\xe0\xc0\xa0") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString; - QTest::newRow("invalid-utf8-4chars-1") << raw("\x64\xf0\x90\x80\xc0") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString; - QTest::newRow("invalid-utf8-4chars-2") << raw("\x64\xf0\x90\xc0\x80") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString; - QTest::newRow("invalid-utf8-4chars-3") << raw("\x64\xf0\xc0\x80\x80") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString; + // UTF-8 sequences with invalid continuation bytes + QTest::newRow("invalid-utf8-bad-continuation-1char") << raw("\x61\x80") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString; + QTest::newRow("invalid-utf8-bad-continuation-2chars-1") << raw("\x62\xc2\xc0") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString; + QTest::newRow("invalid-utf8-bad-continuation-2chars-2") << raw("\x62\xc3\xdf") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString; + QTest::newRow("invalid-utf8-bad-continuation-2chars-3") << raw("\x62\xc7\xf0") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString; + QTest::newRow("invalid-utf8-bad-continuation-3chars-1") << raw("\x63\xe0\xa0\xc0") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString; + QTest::newRow("invalid-utf8-bad-continuation-3chars-2") << raw("\x63\xe0\xc0\xa0") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString; + QTest::newRow("invalid-utf8-bad-continuation-4chars-1") << raw("\x64\xf0\x90\x80\xc0") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString; + QTest::newRow("invalid-utf8-bad-continuation-4chars-2") << raw("\x64\xf0\x90\xc0\x80") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString; + QTest::newRow("invalid-utf8-bad-continuation-4chars-3") << raw("\x64\xf0\xc0\x80\x80") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString; + // Too short UTF-8 sequences (in an array so there's a byte after that would make it valid UTF-8 if it were part of the string) + QTest::newRow("invalid-utf8-too-short-2chars") << raw("\x82\x61\xc2\x80") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString; + QTest::newRow("invalid-utf8-too-short-3chars-1") << raw("\x82\x61\xe0\x80") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString; + QTest::newRow("invalid-utf8-too-short-3chars-2") << raw("\x82\x62\xe0\xa0\x80") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString; + QTest::newRow("invalid-utf8-too-short-4chars-1") << raw("\x82\x61\xf0\x80") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString; + QTest::newRow("invalid-utf8-too-short-4chars-2") << raw("\x82\x62\xf0\x90\x80") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString; + QTest::newRow("invalid-utf8-too-short-4chars-3") << raw("\x82\x63\xf0\x90\x80\x80") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString; + // UTF-16 surrogages encoded in UTF-8 QTest::newRow("invalid-utf8-hi-surrogate") << raw("\x63\xed\xa0\x80") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString; QTest::newRow("invalid-utf8-lo-surrogate") << raw("\x63\xed\xb0\x80") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString; QTest::newRow("invalid-utf8-surrogate-pair") << raw("\x66\xed\xa0\x80\xed\xb0\x80") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString; + // Non-Unicode UTF-8 sequences QTest::newRow("invalid-utf8-non-unicode-1") << raw("\x64\xf4\x90\x80\x80") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString; QTest::newRow("invalid-utf8-non-unicode-2") << raw("\x65\xf8\x88\x80\x80\x80") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString; QTest::newRow("invalid-utf8-non-unicode-3") << raw("\x66\xfc\x84\x80\x80\x80\x80") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString; QTest::newRow("invalid-utf8-non-unicode-4") << raw("\x66\xfd\xbf\xbf\xbf\xbf\xbf") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString; + // invalid bytes in UTF-8 QTest::newRow("invalid-utf8-fe") << raw("\x61\xfe") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString; QTest::newRow("invalid-utf8-ff") << raw("\x61\xff") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString; + // Overlong sequences QTest::newRow("invalid-utf8-overlong-1-2") << raw("\x62\xc1\x81") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString; QTest::newRow("invalid-utf8-overlong-1-3") << raw("\x63\xe0\x81\x81") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString; QTest::newRow("invalid-utf8-overlong-1-4") << raw("\x64\xf0\x80\x81\x81") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString; @@ -1525,12 +1710,11 @@ void tst_Parser::strictValidation() QFETCH(CborError, expectedError); QString decoded; - CborParser parser; - CborValue first; - CborError err = cbor_parser_init(reinterpret_cast(data.constData()), data.length(), 0, &parser, &first); + ParserWrapper w; + CborError err = w.init(data); QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\""); - err = cbor_value_validate(&first, flags); + err = cbor_value_validate(&w.first, flags); QCOMPARE(err, expectedError); } @@ -1549,12 +1733,11 @@ void tst_Parser::incompleteData() QFETCH(QString, expected); for (int len = 0; len < data.length() - 1; ++len) { - CborParser parser; - CborValue first; - CborError err = cbor_parser_init(reinterpret_cast(data.constData()), len, 0, &parser, &first); + ParserWrapper w; + CborError err = w.init(data.constData(), len); if (!err) { QString decoded; - err = parseOne(&first, &decoded); + err = parseOne(&w.first, &decoded); } if (err != CborErrorUnexpectedEOF) qDebug() << "Length is" << len; @@ -1583,14 +1766,13 @@ void tst_Parser::endPointer() QFETCH(int, offset); QString decoded; - CborParser parser; - CborValue first; - CborError err = cbor_parser_init(reinterpret_cast(data.constData()), data.length(), 0, &parser, &first); + ParserWrapper w; + CborError err = w.init(data); QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\""); - err = parseOne(&first, &decoded); + err = parseOne(&w.first, &decoded); QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\""); - QCOMPARE(int(cbor_value_get_next_byte(&first) - reinterpret_cast(data.constBegin())), offset); + QCOMPARE(int(cbor_value_get_next_byte(&w.first) - w.begin()), offset); } void tst_Parser::recursionLimit_data() @@ -1638,24 +1820,23 @@ void tst_Parser::recursionLimit() { QFETCH(QByteArray, data); - CborParser parser; - CborValue first; - CborError err = cbor_parser_init(reinterpret_cast(data.constData()), data.length(), 0, &parser, &first); + ParserWrapper w; + CborError err = w.init(data); QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\""); // check that it is valid: - CborValue it = first; + CborValue it = w.first; { QString dummy; err = parseOne(&it, &dummy); QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\""); } - it = first; + it = w.first; err = cbor_value_advance(&it); QCOMPARE(err, CborErrorNestingTooDeep); - it = first; + it = w.first; if (cbor_value_is_map(&it)) { CborValue dummy; err = cbor_value_map_find_value(&it, "foo", &dummy); diff --git a/src/corelib/serialization/qcborstream.cpp b/src/corelib/serialization/qcborstream.cpp index d062cff067..df38118805 100644 --- a/src/corelib/serialization/qcborstream.cpp +++ b/src/corelib/serialization/qcborstream.cpp @@ -100,6 +100,16 @@ static CborError _cbor_value_dup_string(const CborValue *, void **, size_t *, Cb Q_UNREACHABLE(); return CborErrorInternalError; } +static CborError cbor_value_get_half_float_as_float(const CborValue *, float *) +{ + Q_UNREACHABLE(); + return CborErrorInternalError; +} +static CborError cbor_encode_float_as_half_float(CborEncoder *, float) +{ + Q_UNREACHABLE(); + return CborErrorInternalError; +} QT_WARNING_POP Q_DECLARE_TYPEINFO(CborEncoder, Q_PRIMITIVE_TYPE); -- cgit v1.2.3 From d92f63122b2980c20b9b5de88d3671b4eae6655b Mon Sep 17 00:00:00 2001 From: Paul Lemire Date: Fri, 29 Mar 2019 09:29:58 +0100 Subject: QShaderGenerator: stop abusing from auto everywhere Leads to a huge loss of context for people trying to understand and maintain that code. Replacing with proper types to ensure better readability and maintenance. Change-Id: I9900b743e8b7fe11bcc7db9ce3191c89f8718afc Reviewed-by: Mike Krus --- src/gui/util/qshadergenerator.cpp | 70 ++++++++++++++++--------------- src/gui/util/qshadergraph.cpp | 42 +++++++++---------- src/gui/util/qshadergraphloader.cpp | 76 +++++++++++++++++----------------- src/gui/util/qshadernodesloader.cpp | 82 ++++++++++++++++++------------------- 4 files changed, 137 insertions(+), 133 deletions(-) (limited to 'src') diff --git a/src/gui/util/qshadergenerator.cpp b/src/gui/util/qshadergenerator.cpp index ae45c03fd1..60cf5a2fc5 100644 --- a/src/gui/util/qshadergenerator.cpp +++ b/src/gui/util/qshadergenerator.cpp @@ -260,21 +260,22 @@ namespace QByteArray replaceParameters(const QByteArray &original, const QShaderNode &node, const QShaderFormat &format) { - auto result = original; + QByteArray result = original; - for (const auto ¶meterName : node.parameterNames()) { - const auto placeholder = QByteArray(QByteArrayLiteral("$") + parameterName.toUtf8()); - const auto parameter = node.parameter(parameterName); + const QStringList parameterNames = node.parameterNames(); + for (const QString ¶meterName : parameterNames) { + const QByteArray placeholder = QByteArray(QByteArrayLiteral("$") + parameterName.toUtf8()); + const QVariant parameter = node.parameter(parameterName); if (parameter.userType() == qMetaTypeId()) { - const auto qualifier = parameter.value(); - const auto value = toGlsl(qualifier, format); + const QShaderLanguage::StorageQualifier qualifier = parameter.value(); + const QByteArray value = toGlsl(qualifier, format); result.replace(placeholder, value); } else if (parameter.userType() == qMetaTypeId()) { - const auto type = parameter.value(); - const auto value = toGlsl(type); + const QShaderLanguage::VariableType type = parameter.value(); + const QByteArray value = toGlsl(type); result.replace(placeholder, value); } else { - const auto value = parameter.toString().toUtf8(); + const QByteArray value = parameter.toString().toUtf8(); result.replace(placeholder, value); } } @@ -288,20 +289,20 @@ QByteArray QShaderGenerator::createShaderCode(const QStringList &enabledLayers) auto code = QByteArrayList(); if (format.isValid()) { - const auto isGLES = format.api() == QShaderFormat::OpenGLES; - const auto major = format.version().majorVersion(); - const auto minor = format.version().minorVersion(); + const bool isGLES = format.api() == QShaderFormat::OpenGLES; + const int major = format.version().majorVersion(); + const int minor = format.version().minorVersion(); - const auto version = major == 2 && isGLES ? 100 - : major == 3 && isGLES ? 300 - : major == 2 ? 100 + 10 * (minor + 1) - : major == 3 && minor <= 2 ? 100 + 10 * (minor + 3) - : major * 100 + minor * 10; + const int version = major == 2 && isGLES ? 100 + : major == 3 && isGLES ? 300 + : major == 2 ? 100 + 10 * (minor + 1) + : major == 3 && minor <= 2 ? 100 + 10 * (minor + 3) + : major * 100 + minor * 10; - const auto profile = isGLES && version > 100 ? QByteArrayLiteral(" es") - : version >= 150 && format.api() == QShaderFormat::OpenGLCoreProfile ? QByteArrayLiteral(" core") - : version >= 150 && format.api() == QShaderFormat::OpenGLCompatibilityProfile ? QByteArrayLiteral(" compatibility") - : QByteArray(); + const QByteArray profile = isGLES && version > 100 ? QByteArrayLiteral(" es") + : version >= 150 && format.api() == QShaderFormat::OpenGLCoreProfile ? QByteArrayLiteral(" core") + : version >= 150 && format.api() == QShaderFormat::OpenGLCompatibilityProfile ? QByteArrayLiteral(" compatibility") + : QByteArray(); code << (QByteArrayLiteral("#version ") + QByteArray::number(version) + profile); code << QByteArray(); @@ -313,9 +314,11 @@ QByteArray QShaderGenerator::createShaderCode(const QStringList &enabledLayers) [enabledLayers] (const QString &s) { return enabledLayers.contains(s); }); }; - for (const auto &node : graph.nodes()) { + const QVector nodes = graph.nodes(); + for (const QShaderNode &node : nodes) { if (intersectsEnabledLayers(node.layers())) { - for (const auto &snippet : node.rule(format).headerSnippets) { + const QByteArrayList headerSnippets = node.rule(format).headerSnippets; + for (const QByteArray &snippet : headerSnippets) { code << replaceParameters(snippet, node, format); } } @@ -325,17 +328,18 @@ QByteArray QShaderGenerator::createShaderCode(const QStringList &enabledLayers) code << QByteArrayLiteral("void main()"); code << QByteArrayLiteral("{"); - for (const auto &statement : graph.createStatements(enabledLayers)) { - const auto node = statement.node; - auto line = node.rule(format).substitution; - for (const auto &port : node.ports()) { - const auto portName = port.name; - const auto portDirection = port.direction; - const auto isInput = port.direction == QShaderNodePort::Input; + for (const QShaderGraph::Statement &statement : graph.createStatements(enabledLayers)) { + const QShaderNode node = statement.node; + QByteArray line = node.rule(format).substitution; + const QVector ports = node.ports(); + for (const QShaderNodePort &port : ports) { + const QString portName = port.name; + const QShaderNodePort::Direction portDirection = port.direction; + const bool isInput = port.direction == QShaderNodePort::Input; - const auto portIndex = statement.portIndex(portDirection, portName); - const auto variableIndex = isInput ? statement.inputs.at(portIndex) - : statement.outputs.at(portIndex); + const int portIndex = statement.portIndex(portDirection, portName); + const int variableIndex = isInput ? statement.inputs.at(portIndex) + : statement.outputs.at(portIndex); if (variableIndex < 0) continue; diff --git a/src/gui/util/qshadergraph.cpp b/src/gui/util/qshadergraph.cpp index 828c709a12..40b85ac469 100644 --- a/src/gui/util/qshadergraph.cpp +++ b/src/gui/util/qshadergraph.cpp @@ -82,8 +82,8 @@ namespace auto statement = QShaderGraph::Statement(); statement.node = node; - const auto ports = node.ports(); - for (const auto &port : ports) { + const QVector ports = node.ports(); + for (const QShaderNodePort &port : ports) { if (port.direction == QShaderNodePort::Input) { statement.inputs.append(-1); } else { @@ -99,19 +99,19 @@ namespace const QUuid &uuid) { auto targetStatement = idHash.value(uuid); - for (const auto &edge : edges) { + for (const QShaderGraph::Edge &edge : edges) { if (edge.targetNodeUuid != uuid) continue; - const auto sourceStatement = idHash.value(edge.sourceNodeUuid); - const auto sourcePortIndex = sourceStatement.portIndex(QShaderNodePort::Output, edge.sourcePortName); - const auto targetPortIndex = targetStatement.portIndex(QShaderNodePort::Input, edge.targetPortName); + const QShaderGraph::Statement sourceStatement = idHash.value(edge.sourceNodeUuid); + const int sourcePortIndex = sourceStatement.portIndex(QShaderNodePort::Output, edge.sourcePortName); + const int targetPortIndex = targetStatement.portIndex(QShaderNodePort::Input, edge.targetPortName); if (sourcePortIndex < 0 || targetPortIndex < 0) continue; - const auto &sourceOutputs = sourceStatement.outputs; - auto &targetInputs = targetStatement.inputs; + const QVector sourceOutputs = sourceStatement.outputs; + QVector &targetInputs = targetStatement.inputs; targetInputs[targetPortIndex] = sourceOutputs[sourcePortIndex]; } return targetStatement; @@ -125,9 +125,9 @@ QUuid QShaderGraph::Statement::uuid() const Q_DECL_NOTHROW int QShaderGraph::Statement::portIndex(QShaderNodePort::Direction direction, const QString &portName) const Q_DECL_NOTHROW { - const auto ports = node.ports(); + const QVector ports = node.ports(); int index = 0; - for (const auto &port : ports) { + for (const QShaderNodePort &port : ports) { if (port.name == portName && port.direction == direction) return index; else if (port.direction == direction) @@ -180,7 +180,7 @@ QVector QShaderGraph::createStatements(const QStringLis [enabledLayers] (const QString &s) { return enabledLayers.contains(s); }); }; - const auto enabledNodes = [this, intersectsEnabledLayers] { + const QVector enabledNodes = [this, intersectsEnabledLayers] { auto res = QVector(); std::copy_if(m_nodes.cbegin(), m_nodes.cend(), std::back_inserter(res), @@ -190,7 +190,7 @@ QVector QShaderGraph::createStatements(const QStringLis return res; }(); - const auto enabledEdges = [this, intersectsEnabledLayers] { + const QVector enabledEdges = [this, intersectsEnabledLayers] { auto res = QVector(); std::copy_if(m_edges.cbegin(), m_edges.cend(), std::back_inserter(res), @@ -200,18 +200,18 @@ QVector QShaderGraph::createStatements(const QStringLis return res; }(); - const auto idHash = [enabledNodes] { + const QHash idHash = [enabledNodes] { auto nextVarId = 0; auto res = QHash(); - for (const auto &node : enabledNodes) + for (const QShaderNode &node : enabledNodes) res.insert(node.uuid(), nodeToStatement(node, nextVarId)); return res; }(); auto result = QVector(); - auto currentEdges = enabledEdges; - auto currentUuids = [enabledNodes] { - const auto inputs = copyOutputNodes(enabledNodes); + QVector currentEdges = enabledEdges; + QVector currentUuids = [enabledNodes] { + const QVector inputs = copyOutputNodes(enabledNodes); auto res = QVector(); std::transform(inputs.cbegin(), inputs.cend(), std::back_inserter(res), @@ -226,14 +226,14 @@ QVector QShaderGraph::createStatements(const QStringLis // because we want to track the dependencies from the output nodes and not the // input nodes while (!currentUuids.isEmpty()) { - const auto uuid = currentUuids.takeFirst(); + const QUuid uuid = currentUuids.takeFirst(); result.append(completeStatement(idHash, enabledEdges, uuid)); - const auto outgoing = outgoingEdges(currentEdges, uuid); - for (const auto &outgoingEdge : outgoing) { + const QVector outgoing = outgoingEdges(currentEdges, uuid); + for (const QShaderGraph::Edge &outgoingEdge : outgoing) { currentEdges.removeAll(outgoingEdge); const QUuid nextUuid = outgoingEdge.sourceNodeUuid; - const auto incoming = incomingEdges(currentEdges, nextUuid); + const QVector incoming = incomingEdges(currentEdges, nextUuid); if (incoming.isEmpty()) { currentUuids.append(nextUuid); } diff --git a/src/gui/util/qshadergraphloader.cpp b/src/gui/util/qshadergraphloader.cpp index 99a9f7869e..b9d8318655 100644 --- a/src/gui/util/qshadergraphloader.cpp +++ b/src/gui/util/qshadergraphloader.cpp @@ -99,7 +99,7 @@ void QShaderGraphLoader::load() return; auto error = QJsonParseError(); - const auto document = QJsonDocument::fromJson(m_device->readAll(), &error); + const QJsonDocument document = QJsonDocument::fromJson(m_device->readAll(), &error); if (error.error != QJsonParseError::NoError) { qWarning() << "Invalid JSON document:" << error.errorString(); @@ -113,16 +113,16 @@ void QShaderGraphLoader::load() return; } - const auto root = document.object(); + const QJsonObject root = document.object(); - const auto nodesValue = root.value(QStringLiteral("nodes")); + const QJsonValue nodesValue = root.value(QStringLiteral("nodes")); if (!nodesValue.isArray()) { qWarning() << "Invalid nodes property, should be an array"; m_status = Error; return; } - const auto edgesValue = root.value(QStringLiteral("edges")); + const QJsonValue edgesValue = root.value(QStringLiteral("edges")); if (!edgesValue.isArray()) { qWarning() << "Invalid edges property, should be an array"; m_status = Error; @@ -131,7 +131,7 @@ void QShaderGraphLoader::load() bool hasError = false; - const auto prototypesValue = root.value(QStringLiteral("prototypes")); + const QJsonValue prototypesValue = root.value(QStringLiteral("prototypes")); if (!prototypesValue.isUndefined()) { if (prototypesValue.isObject()) { QShaderNodesLoader loader; @@ -144,60 +144,60 @@ void QShaderGraphLoader::load() } } - const auto nodes = nodesValue.toArray(); - for (const auto &nodeValue : nodes) { + const QJsonArray nodes = nodesValue.toArray(); + for (const QJsonValue &nodeValue : nodes) { if (!nodeValue.isObject()) { qWarning() << "Invalid node found"; hasError = true; continue; } - const auto nodeObject = nodeValue.toObject(); + const QJsonObject nodeObject = nodeValue.toObject(); - const auto uuidString = nodeObject.value(QStringLiteral("uuid")).toString(); - const auto uuid = QUuid(uuidString); + const QString uuidString = nodeObject.value(QStringLiteral("uuid")).toString(); + const QUuid uuid = QUuid(uuidString); if (uuid.isNull()) { qWarning() << "Invalid UUID found in node:" << uuidString; hasError = true; continue; } - const auto type = nodeObject.value(QStringLiteral("type")).toString(); + const QString type = nodeObject.value(QStringLiteral("type")).toString(); if (!m_prototypes.contains(type)) { qWarning() << "Unsupported node type found:" << type; hasError = true; continue; } - const auto layersArray = nodeObject.value(QStringLiteral("layers")).toArray(); + const QJsonArray layersArray = nodeObject.value(QStringLiteral("layers")).toArray(); auto layers = QStringList(); - for (const auto &layerValue : layersArray) { + for (const QJsonValue &layerValue : layersArray) { layers.append(layerValue.toString()); } - auto node = m_prototypes.value(type); + QShaderNode node = m_prototypes.value(type); node.setUuid(uuid); node.setLayers(layers); - const auto parametersValue = nodeObject.value(QStringLiteral("parameters")); + const QJsonValue parametersValue = nodeObject.value(QStringLiteral("parameters")); if (parametersValue.isObject()) { - const auto parametersObject = parametersValue.toObject(); - for (const auto ¶meterName : parametersObject.keys()) { - const auto parameterValue = parametersObject.value(parameterName); + const QJsonObject parametersObject = parametersValue.toObject(); + for (const QString ¶meterName : parametersObject.keys()) { + const QJsonValue parameterValue = parametersObject.value(parameterName); if (parameterValue.isObject()) { - const auto parameterObject = parameterValue.toObject(); - const auto type = parameterObject.value(QStringLiteral("type")).toString(); - const auto typeId = QMetaType::type(type.toUtf8()); + const QJsonObject parameterObject = parameterValue.toObject(); + const QString type = parameterObject.value(QStringLiteral("type")).toString(); + const int typeId = QMetaType::type(type.toUtf8()); - const auto value = parameterObject.value(QStringLiteral("value")).toString(); + const QString value = parameterObject.value(QStringLiteral("value")).toString(); auto variant = QVariant(value); if (QMetaType::typeFlags(typeId) & QMetaType::IsEnumeration) { - const auto metaObject = QMetaType::metaObjectForType(typeId); - const auto className = metaObject->className(); - const auto enumName = type.mid(static_cast(qstrlen(className)) + 2).toUtf8(); - const auto metaEnum = metaObject->enumerator(metaObject->indexOfEnumerator(enumName)); - const auto enumValue = metaEnum.keyToValue(value.toUtf8()); + const QMetaObject *metaObject = QMetaType::metaObjectForType(typeId); + const char *className = metaObject->className(); + const QByteArray enumName = type.mid(static_cast(qstrlen(className)) + 2).toUtf8(); + const QMetaEnum metaEnum = metaObject->enumerator(metaObject->indexOfEnumerator(enumName)); + const int enumValue = metaEnum.keyToValue(value.toUtf8()); variant = QVariant(enumValue); variant.convert(typeId); } else { @@ -213,39 +213,39 @@ void QShaderGraphLoader::load() m_graph.addNode(node); } - const auto edges = edgesValue.toArray(); - for (const auto &edgeValue : edges) { + const QJsonArray edges = edgesValue.toArray(); + for (const QJsonValue &edgeValue : edges) { if (!edgeValue.isObject()) { qWarning() << "Invalid edge found"; hasError = true; continue; } - const auto edgeObject = edgeValue.toObject(); + const QJsonObject edgeObject = edgeValue.toObject(); - const auto sourceUuidString = edgeObject.value(QStringLiteral("sourceUuid")).toString(); - const auto sourceUuid = QUuid(sourceUuidString); + const QString sourceUuidString = edgeObject.value(QStringLiteral("sourceUuid")).toString(); + const QUuid sourceUuid = QUuid(sourceUuidString); if (sourceUuid.isNull()) { qWarning() << "Invalid source UUID found in edge:" << sourceUuidString; hasError = true; continue; } - const auto sourcePort = edgeObject.value(QStringLiteral("sourcePort")).toString(); + const QString sourcePort = edgeObject.value(QStringLiteral("sourcePort")).toString(); - const auto targetUuidString = edgeObject.value(QStringLiteral("targetUuid")).toString(); - const auto targetUuid = QUuid(targetUuidString); + const QString targetUuidString = edgeObject.value(QStringLiteral("targetUuid")).toString(); + const QUuid targetUuid = QUuid(targetUuidString); if (targetUuid.isNull()) { qWarning() << "Invalid target UUID found in edge:" << targetUuidString; hasError = true; continue; } - const auto targetPort = edgeObject.value(QStringLiteral("targetPort")).toString(); + const QString targetPort = edgeObject.value(QStringLiteral("targetPort")).toString(); - const auto layersArray = edgeObject.value(QStringLiteral("layers")).toArray(); + const QJsonArray layersArray = edgeObject.value(QStringLiteral("layers")).toArray(); auto layers = QStringList(); - for (const auto &layerValue : layersArray) { + for (const QJsonValue &layerValue : layersArray) { layers.append(layerValue.toString()); } diff --git a/src/gui/util/qshadernodesloader.cpp b/src/gui/util/qshadernodesloader.cpp index 692653ee44..9badbb94df 100644 --- a/src/gui/util/qshadernodesloader.cpp +++ b/src/gui/util/qshadernodesloader.cpp @@ -84,7 +84,7 @@ void QShaderNodesLoader::load() return; auto error = QJsonParseError(); - const auto document = QJsonDocument::fromJson(m_device->readAll(), &error); + const QJsonDocument document = QJsonDocument::fromJson(m_device->readAll(), &error); if (error.error != QJsonParseError::NoError) { qWarning() << "Invalid JSON document:" << error.errorString(); @@ -98,7 +98,7 @@ void QShaderNodesLoader::load() return; } - const auto root = document.object(); + const QJsonObject root = document.object(); load(root); } @@ -106,22 +106,22 @@ void QShaderNodesLoader::load(const QJsonObject &prototypesObject) { bool hasError = false; - for (const auto &property : prototypesObject.keys()) { - const auto nodeValue = prototypesObject.value(property); + for (const QString &property : prototypesObject.keys()) { + const QJsonValue nodeValue = prototypesObject.value(property); if (!nodeValue.isObject()) { qWarning() << "Invalid node found"; hasError = true; break; } - const auto nodeObject = nodeValue.toObject(); + const QJsonObject nodeObject = nodeValue.toObject(); auto node = QShaderNode(); - const auto inputsValue = nodeObject.value(QStringLiteral("inputs")); + const QJsonValue inputsValue = nodeObject.value(QStringLiteral("inputs")); if (inputsValue.isArray()) { - const auto inputsArray = inputsValue.toArray(); - for (const auto &inputValue : inputsArray) { + const QJsonArray inputsArray = inputsValue.toArray(); + for (const QJsonValue &inputValue : inputsArray) { if (!inputValue.isString()) { qWarning() << "Non-string value in inputs"; hasError = true; @@ -135,10 +135,10 @@ void QShaderNodesLoader::load(const QJsonObject &prototypesObject) } } - const auto outputsValue = nodeObject.value(QStringLiteral("outputs")); + const QJsonValue outputsValue = nodeObject.value(QStringLiteral("outputs")); if (outputsValue.isArray()) { - const auto outputsArray = outputsValue.toArray(); - for (const auto &outputValue : outputsArray) { + const QJsonArray outputsArray = outputsValue.toArray(); + for (const QJsonValue &outputValue : outputsArray) { if (!outputValue.isString()) { qWarning() << "Non-string value in outputs"; hasError = true; @@ -152,25 +152,25 @@ void QShaderNodesLoader::load(const QJsonObject &prototypesObject) } } - const auto parametersValue = nodeObject.value(QStringLiteral("parameters")); + const QJsonValue parametersValue = nodeObject.value(QStringLiteral("parameters")); if (parametersValue.isObject()) { - const auto parametersObject = parametersValue.toObject(); - for (const auto ¶meterName : parametersObject.keys()) { - const auto parameterValue = parametersObject.value(parameterName); + const QJsonObject parametersObject = parametersValue.toObject(); + for (const QString ¶meterName : parametersObject.keys()) { + const QJsonValue parameterValue = parametersObject.value(parameterName); if (parameterValue.isObject()) { - const auto parameterObject = parameterValue.toObject(); - const auto type = parameterObject.value(QStringLiteral("type")).toString(); - const auto typeId = QMetaType::type(type.toUtf8()); + const QJsonObject parameterObject = parameterValue.toObject(); + const QString type = parameterObject.value(QStringLiteral("type")).toString(); + const int typeId = QMetaType::type(type.toUtf8()); - const auto value = parameterObject.value(QStringLiteral("value")).toString(); + const QString value = parameterObject.value(QStringLiteral("value")).toString(); auto variant = QVariant(value); if (QMetaType::typeFlags(typeId) & QMetaType::IsEnumeration) { - const auto metaObject = QMetaType::metaObjectForType(typeId); - const auto className = metaObject->className(); - const auto enumName = type.mid(static_cast(qstrlen(className)) + 2).toUtf8(); - const auto metaEnum = metaObject->enumerator(metaObject->indexOfEnumerator(enumName)); - const auto enumValue = metaEnum.keyToValue(value.toUtf8()); + const QMetaObject *metaObject = QMetaType::metaObjectForType(typeId); + const char *className = metaObject->className(); + const QByteArray enumName = type.mid(static_cast(qstrlen(className)) + 2).toUtf8(); + const QMetaEnum metaEnum = metaObject->enumerator(metaObject->indexOfEnumerator(enumName)); + const int enumValue = metaEnum.keyToValue(value.toUtf8()); variant = QVariant(enumValue); variant.convert(typeId); } else { @@ -183,36 +183,36 @@ void QShaderNodesLoader::load(const QJsonObject &prototypesObject) } } - const auto rulesValue = nodeObject.value(QStringLiteral("rules")); + const QJsonValue rulesValue = nodeObject.value(QStringLiteral("rules")); if (rulesValue.isArray()) { - const auto rulesArray = rulesValue.toArray(); - for (const auto &ruleValue : rulesArray) { + const QJsonArray rulesArray = rulesValue.toArray(); + for (const QJsonValue &ruleValue : rulesArray) { if (!ruleValue.isObject()) { qWarning() << "Rules should be objects"; hasError = true; break; } - const auto ruleObject = ruleValue.toObject(); + const QJsonObject ruleObject = ruleValue.toObject(); - const auto formatValue = ruleObject.value(QStringLiteral("format")); + const QJsonValue formatValue = ruleObject.value(QStringLiteral("format")); if (!formatValue.isObject()) { qWarning() << "Format is mandatory in rules and should be an object"; hasError = true; break; } - const auto formatObject = formatValue.toObject(); + const QJsonObject formatObject = formatValue.toObject(); auto format = QShaderFormat(); - const auto apiValue = formatObject.value(QStringLiteral("api")); + const QJsonValue apiValue = formatObject.value(QStringLiteral("api")); if (!apiValue.isString()) { qWarning() << "Format API must be a string"; hasError = true; break; } - const auto api = apiValue.toString(); + const QString api = apiValue.toString(); format.setApi(api == QStringLiteral("OpenGLES") ? QShaderFormat::OpenGLES : api == QStringLiteral("OpenGLNoProfile") ? QShaderFormat::OpenGLNoProfile : api == QStringLiteral("OpenGLCoreProfile") ? QShaderFormat::OpenGLCoreProfile @@ -224,8 +224,8 @@ void QShaderNodesLoader::load(const QJsonObject &prototypesObject) break; } - const auto majorValue = formatObject.value(QStringLiteral("major")); - const auto minorValue = formatObject.value(QStringLiteral("minor")); + const QJsonValue majorValue = formatObject.value(QStringLiteral("major")); + const QJsonValue minorValue = formatObject.value(QStringLiteral("minor")); if (!majorValue.isDouble() || !minorValue.isDouble()) { qWarning() << "Format major and minor version must be values"; hasError = true; @@ -233,28 +233,28 @@ void QShaderNodesLoader::load(const QJsonObject &prototypesObject) } format.setVersion(QVersionNumber(majorValue.toInt(), minorValue.toInt())); - const auto extensionsValue = formatObject.value(QStringLiteral("extensions")); - const auto extensionsArray = extensionsValue.toArray(); + const QJsonValue extensionsValue = formatObject.value(QStringLiteral("extensions")); + const QJsonArray extensionsArray = extensionsValue.toArray(); auto extensions = QStringList(); std::transform(extensionsArray.constBegin(), extensionsArray.constEnd(), std::back_inserter(extensions), [] (const QJsonValue &extensionValue) { return extensionValue.toString(); }); format.setExtensions(extensions); - const auto vendor = formatObject.value(QStringLiteral("vendor")).toString(); + const QString vendor = formatObject.value(QStringLiteral("vendor")).toString(); format.setVendor(vendor); - const auto substitutionValue = ruleObject.value(QStringLiteral("substitution")); + const QJsonValue substitutionValue = ruleObject.value(QStringLiteral("substitution")); if (!substitutionValue.isString()) { qWarning() << "Substitution needs to be a string"; hasError = true; break; } - const auto substitution = substitutionValue.toString().toUtf8(); + const QByteArray substitution = substitutionValue.toString().toUtf8(); - const auto snippetsValue = ruleObject.value(QStringLiteral("headerSnippets")); - const auto snippetsArray = snippetsValue.toArray(); + const QJsonValue snippetsValue = ruleObject.value(QStringLiteral("headerSnippets")); + const QJsonArray snippetsArray = snippetsValue.toArray(); auto snippets = QByteArrayList(); std::transform(snippetsArray.constBegin(), snippetsArray.constEnd(), std::back_inserter(snippets), -- cgit v1.2.3 From e251f1184925ad4f0c2e18843343e9df690d8302 Mon Sep 17 00:00:00 2001 From: Kai Koehne Date: Fri, 5 Apr 2019 15:31:14 +0200 Subject: printsupport: Fix clang-cl warning qprintengine_win.cpp(1117,14): warning: comparison of two values with different enumeration types in switch statement ('QPrint::DuplexMode' and 'QPrinter::DuplexMode') [-Wenum-compare-switch] case QPrinter::DuplexShortSide: Change-Id: Ib5028d80ecf7f6bb9eb0562e5c137acfeb709a14 Reviewed-by: Friedemann Kleint --- src/printsupport/kernel/qprintengine_win.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/printsupport/kernel/qprintengine_win.cpp b/src/printsupport/kernel/qprintengine_win.cpp index e3a5c3d2e8..add57e9d95 100644 --- a/src/printsupport/kernel/qprintengine_win.cpp +++ b/src/printsupport/kernel/qprintengine_win.cpp @@ -1105,16 +1105,16 @@ void QWin32PrintEngine::setProperty(PrintEnginePropertyKey key, const QVariant & if (mode == property(PPK_Duplex).toInt() || !d->m_printDevice.supportedDuplexModes().contains(mode)) break; switch (mode) { - case QPrinter::DuplexNone: + case QPrint::DuplexNone: d->devMode->dmDuplex = DMDUP_SIMPLEX; break; - case QPrinter::DuplexAuto: + case QPrint::DuplexAuto: d->devMode->dmDuplex = d->m_pageLayout.orientation() == QPageLayout::Landscape ? DMDUP_HORIZONTAL : DMDUP_VERTICAL; break; - case QPrinter::DuplexLongSide: + case QPrint::DuplexLongSide: d->devMode->dmDuplex = DMDUP_VERTICAL; break; - case QPrinter::DuplexShortSide: + case QPrint::DuplexShortSide: d->devMode->dmDuplex = DMDUP_HORIZONTAL; break; default: -- cgit v1.2.3 From 0adb78a8479417c902cde9ba050edc2f828ecd83 Mon Sep 17 00:00:00 2001 From: Kai Koehne Date: Fri, 5 Apr 2019 11:13:30 +0200 Subject: QElapsedTimer: Remove unused static nanosecondsToTicks method Fixes clang-cl warning qelapsedtimer_win.cpp(80,22): warning: unused function 'nanosecondsToTicks' [-Wunused-function] Change-Id: I1ff334049fcf4b265fe97235b7daf06969331313 Reviewed-by: Thiago Macieira --- src/corelib/kernel/qelapsedtimer_win.cpp | 9 --------- 1 file changed, 9 deletions(-) (limited to 'src') diff --git a/src/corelib/kernel/qelapsedtimer_win.cpp b/src/corelib/kernel/qelapsedtimer_win.cpp index a63290d2f8..3beb158b8a 100644 --- a/src/corelib/kernel/qelapsedtimer_win.cpp +++ b/src/corelib/kernel/qelapsedtimer_win.cpp @@ -77,15 +77,6 @@ static inline qint64 ticksToNanoseconds(qint64 ticks) return ticks * 1000000; } -static inline qint64 nanosecondsToTicks(qint64 nsec) -{ - if (counterFrequency > 0) { - // QueryPerformanceCounter uses an arbitrary frequency - return double(nsec) * counterFrequency / 1000000000.; - } - // GetTickCount(64) uses milliseconds - return nsec / 1000000; -} static quint64 getTickCount() { -- cgit v1.2.3 From 6d4a456a28282973d2501e0b16f09cafb316bb0a Mon Sep 17 00:00:00 2001 From: Edward Welbourne Date: Fri, 5 Apr 2019 11:25:13 +0200 Subject: Fix off-by-one error in QTranslatorPrivate::do_load() The central loop starts by reading five bytes; but the loop condition only checked that four were available. Change-Id: I244cecacabeffbac10ad94081f32847f912d95d9 Reviewed-by: Kai Koehne Reviewed-by: Thiago Macieira Reviewed-by: hjk --- src/corelib/kernel/qtranslator.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/corelib/kernel/qtranslator.cpp b/src/corelib/kernel/qtranslator.cpp index 929554f6bc..63aeed07c3 100644 --- a/src/corelib/kernel/qtranslator.cpp +++ b/src/corelib/kernel/qtranslator.cpp @@ -824,7 +824,7 @@ bool QTranslatorPrivate::do_load(const uchar *data, int len, const QString &dire data += MagicLength; QStringList dependencies; - while (data < end - 4) { + while (data < end - 5) { quint8 tag = read8(data++); quint32 blockLen = read32(data); data += 4; -- cgit v1.2.3 From 5f2afe18ccb0bbe258d4016ef65218cd3656cac2 Mon Sep 17 00:00:00 2001 From: Milian Wolff Date: Tue, 9 Apr 2019 13:38:06 +0200 Subject: Fix QMetaObject::newInstance on non-QObject meta object QMetaObject::newInstance returns a QObject, thus it's not possible to create a new instance of a Q_GADGET using this function. Previously, we returned a non-null QObject pointer for such scenarios, which then leads to crashes when one tries to use it. Now, we check whether the meta object inherits QObject's meta object, and error out early otherwise. Change-Id: I7b1fb6c8d48b3e98161894be2f281a491963345e Reviewed-by: Thiago Macieira --- src/corelib/kernel/qmetaobject.cpp | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src') diff --git a/src/corelib/kernel/qmetaobject.cpp b/src/corelib/kernel/qmetaobject.cpp index b8b5c0de46..666bb6eace 100644 --- a/src/corelib/kernel/qmetaobject.cpp +++ b/src/corelib/kernel/qmetaobject.cpp @@ -235,6 +235,12 @@ QObject *QMetaObject::newInstance(QGenericArgument val0, QGenericArgument val8, QGenericArgument val9) const { + if (!inherits(&QObject::staticMetaObject)) + { + qWarning("QMetaObject::newInstance: type %s does not inherit QObject", className()); + return nullptr; + } + QByteArray constructorName = className(); { int idx = constructorName.lastIndexOf(':'); -- cgit v1.2.3 From 37c24c6b1b65c2ff9808e5c2e2a18cf496e4a9db Mon Sep 17 00:00:00 2001 From: Christian Ehrlicher Date: Thu, 4 Apr 2019 20:16:18 +0200 Subject: QTableView: fix Ctrl+End behavior with disabled columns Ctrl+End moves the visual index to the bottom left index. This does not work correctly when the item in the bottom left is disabled. It should be fixed with 7863be311570fa219066df5fe8720d5b92ddb680 but does not due to a typo. Fix the typo by using the newly calculated visualColumn instead the initial column. There are cases where the algorithm still does not work as expected when there are more disabled items but fixing them would add a lot of complexity with no (much) gain. Fixes: QTBUG-72400 Change-Id: Ie90f6b3e41e00f54e826c2b4e7303e85ac1e4115 Reviewed-by: Richard Moe Gustavsen --- src/widgets/itemviews/qtableview.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/widgets/itemviews/qtableview.cpp b/src/widgets/itemviews/qtableview.cpp index 9c509583e6..e1280b250a 100644 --- a/src/widgets/itemviews/qtableview.cpp +++ b/src/widgets/itemviews/qtableview.cpp @@ -1870,7 +1870,7 @@ QModelIndex QTableView::moveCursor(CursorAction cursorAction, Qt::KeyboardModifi visualColumn = d->nextActiveVisualColumn(visualRow, right, -1, QTableViewPrivate::SearchDirection::Decreasing); if (modifiers & Qt::ControlModifier) - visualRow = d->nextActiveVisualRow(bottom, current.column(), -1, + visualRow = d->nextActiveVisualRow(bottom, visualColumn, -1, QTableViewPrivate::SearchDirection::Decreasing); break; case MovePageUp: { -- cgit v1.2.3 From 1029a2e01051cd35452941e7b49b36520481cdf0 Mon Sep 17 00:00:00 2001 From: Christian Ehrlicher Date: Fri, 29 Mar 2019 21:18:26 +0100 Subject: QTableView: don't draw additional grid lines top and left QTableView drew additional grid lines on the top and left side when the corresponding header was not visible and the ScrollMode was ScrollPerItem. After 8f2bacea41443af8564ff78f284016b6615a001b they were also drawn for ScrolPerPixel for consistency. But they are not needed at all and only create visual artifacts. Therefore remove the drawing of the additional lines completely. Fixes: QTBUG-74706 Change-Id: I5c77d53a2eeefab9b9bfe0efea6439f5afede4ac Reviewed-by: Friedemann Kleint Reviewed-by: Andy Shaw --- src/widgets/itemviews/qtableview.cpp | 23 ----------------------- 1 file changed, 23 deletions(-) (limited to 'src') diff --git a/src/widgets/itemviews/qtableview.cpp b/src/widgets/itemviews/qtableview.cpp index e1280b250a..8fe5b70332 100644 --- a/src/widgets/itemviews/qtableview.cpp +++ b/src/widgets/itemviews/qtableview.cpp @@ -1573,29 +1573,6 @@ void QTableView::paintEvent(QPaintEvent *event) colp += columnWidth(col) - gridSize; painter.drawLine(colp, dirtyArea.top(), colp, dirtyArea.bottom()); } - - //draw the top & left grid lines if the headers are not visible. - //We do update this line when subsequent scroll happen (see scrollContentsBy) - if (horizontalHeader->isHidden() && top == 0) { - const int row = verticalHeader->logicalIndex(top); - if (!verticalHeader->isSectionHidden(row)) { - const int rowY = rowViewportPosition(row) + offset.y(); - if (rowY == dirtyArea.top()) - painter.drawLine(dirtyArea.left(), rowY, dirtyArea.right(), rowY); - } - } - if (verticalHeader->isHidden() && left == 0) { - const int col = horizontalHeader->logicalIndex(left); - if (!horizontalHeader->isSectionHidden(col)) { - int colX = columnViewportPosition(col) + offset.x(); - if (!isLeftToRight()) - colX += columnWidth(left) - 1; - if (isLeftToRight() && colX == dirtyArea.left()) - painter.drawLine(colX, dirtyArea.top(), colX, dirtyArea.bottom()); - if (!isLeftToRight() && colX == dirtyArea.right()) - painter.drawLine(colX, dirtyArea.top(), colX, dirtyArea.bottom()); - } - } painter.setPen(old); } } -- cgit v1.2.3