Merge remote-tracking branch 'origin/5.13' into dev
Conflicts: src/widgets/styles/qstyle_p.h Change-Id: I0e6e856bd6628da1135b3ba674dddffabbeb5c09
This commit is contained in:
commit
c7af193d2e
@ -242,7 +242,8 @@ static int doLink(int argc, char **argv)
|
||||
|
||||
#endif
|
||||
|
||||
static int installFile(const QString &source, const QString &target, bool exe = false)
|
||||
static int installFile(const QString &source, const QString &target, bool exe = false,
|
||||
bool preservePermissions = false)
|
||||
{
|
||||
QFile sourceFile(source);
|
||||
QFile targetFile(target);
|
||||
@ -260,35 +261,32 @@ static int installFile(const QString &source, const QString &target, bool exe =
|
||||
return 3;
|
||||
}
|
||||
|
||||
QFileDevice::Permissions targetPermissions = preservePermissions
|
||||
? sourceFile.permissions()
|
||||
: (QFileDevice::ReadOwner | QFileDevice::WriteOwner
|
||||
| QFileDevice::ReadUser | QFileDevice::WriteUser
|
||||
| QFileDevice::ReadGroup | QFileDevice::ReadOther);
|
||||
if (exe) {
|
||||
if (!targetFile.setPermissions(sourceFile.permissions() | QFileDevice::ExeOwner | QFileDevice::ExeUser |
|
||||
QFileDevice::ExeGroup | QFileDevice::ExeOther)) {
|
||||
fprintf(stderr, "Error setting execute permissions on %s: %s\n",
|
||||
qPrintable(target), qPrintable(targetFile.errorString()));
|
||||
return 3;
|
||||
}
|
||||
targetPermissions |= QFileDevice::ExeOwner | QFileDevice::ExeUser |
|
||||
QFileDevice::ExeGroup | QFileDevice::ExeOther;
|
||||
}
|
||||
if (!targetFile.setPermissions(targetPermissions)) {
|
||||
fprintf(stderr, "Error setting permissions on %s: %s\n",
|
||||
qPrintable(target), qPrintable(targetFile.errorString()));
|
||||
return 3;
|
||||
}
|
||||
|
||||
// Copy file times
|
||||
QString error;
|
||||
#ifdef Q_OS_WIN
|
||||
const QFile::Permissions permissions = targetFile.permissions();
|
||||
const bool readOnly = !(permissions & QFile::WriteUser);
|
||||
if (readOnly)
|
||||
targetFile.setPermissions(permissions | QFile::WriteUser);
|
||||
#endif
|
||||
if (!IoUtils::touchFile(target, sourceFile.fileName(), &error)) {
|
||||
fprintf(stderr, "%s", qPrintable(error));
|
||||
return 3;
|
||||
}
|
||||
#ifdef Q_OS_WIN
|
||||
if (readOnly)
|
||||
targetFile.setPermissions(permissions);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int installFileOrDirectory(const QString &source, const QString &target)
|
||||
static int installFileOrDirectory(const QString &source, const QString &target,
|
||||
bool preservePermissions = false)
|
||||
{
|
||||
QFileInfo fi(source);
|
||||
if (false) {
|
||||
@ -308,18 +306,18 @@ static int installFileOrDirectory(const QString &source, const QString &target)
|
||||
} else if (fi.isDir()) {
|
||||
QDir::current().mkpath(target);
|
||||
|
||||
QDirIterator it(source, QDir::AllEntries | QDir::NoDotAndDotDot);
|
||||
QDirIterator it(source, QDir::AllEntries | QDir::NoDotAndDotDot | QDir::Hidden);
|
||||
while (it.hasNext()) {
|
||||
it.next();
|
||||
const QFileInfo &entry = it.fileInfo();
|
||||
const QString &entryTarget = target + QDir::separator() + entry.fileName();
|
||||
|
||||
const int recursionResult = installFileOrDirectory(entry.filePath(), entryTarget);
|
||||
const int recursionResult = installFileOrDirectory(entry.filePath(), entryTarget, true);
|
||||
if (recursionResult != 0)
|
||||
return recursionResult;
|
||||
}
|
||||
} else {
|
||||
const int fileCopyResult = installFile(source, target);
|
||||
const int fileCopyResult = installFile(source, target, /*exe*/ false, preservePermissions);
|
||||
if (fileCopyResult != 0)
|
||||
return fileCopyResult;
|
||||
}
|
||||
|
4
src/3rdparty/tinycbor/src/cbor.h
vendored
4
src/3rdparty/tinycbor/src/cbor.h
vendored
@ -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;
|
||||
}
|
||||
|
24
src/3rdparty/tinycbor/src/cborencoder.c
vendored
24
src/3rdparty/tinycbor/src/cborencoder.c
vendored
@ -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()
|
||||
*/
|
||||
|
||||
/**
|
||||
|
2
src/3rdparty/tinycbor/src/cborparser.c
vendored
2
src/3rdparty/tinycbor/src/cborparser.c
vendored
@ -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()
|
||||
*/
|
||||
|
||||
/** @} */
|
||||
|
@ -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
|
||||
|
36
src/3rdparty/tinycbor/tests/encoder/data.cpp
vendored
36
src/3rdparty/tinycbor/tests/encoder/data.cpp
vendored
@ -123,6 +123,42 @@ QVariant make_ilmap(const std::initializer_list<QPair<QVariant, QVariant>> &list
|
||||
return QVariant::fromValue(IndeterminateLengthMap(list));
|
||||
}
|
||||
|
||||
void addHalfFloat()
|
||||
{
|
||||
QTest::addColumn<QByteArray>("output");
|
||||
QTest::addColumn<unsigned>("rawInput");
|
||||
QTest::addColumn<double>("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<QByteArray>("output");
|
||||
|
125
src/3rdparty/tinycbor/tests/encoder/tst_encoder.cpp
vendored
125
src/3rdparty/tinycbor/tests/encoder/tst_encoder.cpp
vendored
@ -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 <typename Input, typename FnUnderTest>
|
||||
void encodeOne(Input input, FnUnderTest fn_under_test, QByteArray &buffer, CborError &error)
|
||||
{
|
||||
QByteArray buffer(output.length(), Qt::Uninitialized);
|
||||
uint8_t *bufptr = reinterpret_cast<quint8 *>(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);
|
||||
|
||||
buffer.resize(int(cbor_encoder_get_buffer_size(&encoder, bufptr)));
|
||||
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)));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Input, typename FnUnderTest>
|
||||
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<double>("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();
|
||||
|
377
src/3rdparty/tinycbor/tests/parser/tst_parser.cpp
vendored
377
src/3rdparty/tinycbor/tests/parser/tst_parser.cpp
vendored
@ -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 <QtTest>
|
||||
#include "cbor.h"
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#if defined(Q_OS_UNIX)
|
||||
# include <sys/mman.h>
|
||||
# include <unistd.h>
|
||||
#elif defined(Q_OS_WIN)
|
||||
# define WIN32_LEAN_AND_MEAN 1
|
||||
# define NOMINMAX 1
|
||||
# include <windows.h>
|
||||
#endif
|
||||
|
||||
|
||||
namespace QTest {
|
||||
template<> char *toString<CborError>(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<uint8_t *>(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<uint8_t *>(realdata);
|
||||
ptr += alloc - PageSize;
|
||||
VirtualProtect(ptr, PageSize, PAGE_NOACCESS, nullptr);
|
||||
|
||||
ptr -= n;
|
||||
return ptr;
|
||||
#endif
|
||||
}
|
||||
realdata = malloc(n);
|
||||
return static_cast<uint8_t *>(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<QString *>(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<const quint8 *>(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<const quint8 *>(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<QByteArray>("data");
|
||||
QTest::addColumn<unsigned>("expectedRaw");
|
||||
QTest::addColumn<double>("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<const quint8 *>(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<const quint8 *>(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<const quint8 *>(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<const quint8 *>(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<const quint8 *>(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<const quint8 *>(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<int>::min() || expected > std::numeric_limits<int>::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<const quint8 *>(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<const quint8 *>(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<const quint8 *>(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<const quint8 *>(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<const quint8 *>(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<const quint8 *>(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);
|
||||
|
@ -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()
|
||||
{
|
||||
|
@ -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(':');
|
||||
|
@ -817,7 +817,7 @@ bool QTranslatorPrivate::do_load(const uchar *data, qsizetype len, const QString
|
||||
data += MagicLength;
|
||||
|
||||
QStringList dependencies;
|
||||
while (data < end - 4) {
|
||||
while (data < end - 5) {
|
||||
quint8 tag = read8(data++);
|
||||
quint32 blockLen = read32(data);
|
||||
data += 4;
|
||||
|
@ -101,6 +101,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);
|
||||
|
@ -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<QShaderLanguage::StorageQualifier>()) {
|
||||
const auto qualifier = parameter.value<QShaderLanguage::StorageQualifier>();
|
||||
const auto value = toGlsl(qualifier, format);
|
||||
const QShaderLanguage::StorageQualifier qualifier = parameter.value<QShaderLanguage::StorageQualifier>();
|
||||
const QByteArray value = toGlsl(qualifier, format);
|
||||
result.replace(placeholder, value);
|
||||
} else if (parameter.userType() == qMetaTypeId<QShaderLanguage::VariableType>()) {
|
||||
const auto type = parameter.value<QShaderLanguage::VariableType>();
|
||||
const auto value = toGlsl(type);
|
||||
const QShaderLanguage::VariableType type = parameter.value<QShaderLanguage::VariableType>();
|
||||
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<QShaderNode> 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<QShaderNodePort> 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;
|
||||
|
||||
|
@ -82,8 +82,8 @@ namespace
|
||||
auto statement = QShaderGraph::Statement();
|
||||
statement.node = node;
|
||||
|
||||
const auto ports = node.ports();
|
||||
for (const auto &port : ports) {
|
||||
const QVector<QShaderNodePort> 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<int> sourceOutputs = sourceStatement.outputs;
|
||||
QVector<int> &targetInputs = targetStatement.inputs;
|
||||
targetInputs[targetPortIndex] = sourceOutputs[sourcePortIndex];
|
||||
}
|
||||
return targetStatement;
|
||||
@ -125,9 +125,9 @@ QUuid QShaderGraph::Statement::uuid() const noexcept
|
||||
|
||||
int QShaderGraph::Statement::portIndex(QShaderNodePort::Direction direction, const QString &portName) const noexcept
|
||||
{
|
||||
const auto ports = node.ports();
|
||||
const QVector<QShaderNodePort> 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::Statement> QShaderGraph::createStatements(const QStringLis
|
||||
[enabledLayers] (const QString &s) { return enabledLayers.contains(s); });
|
||||
};
|
||||
|
||||
const auto enabledNodes = [this, intersectsEnabledLayers] {
|
||||
const QVector<QShaderNode> enabledNodes = [this, intersectsEnabledLayers] {
|
||||
auto res = QVector<QShaderNode>();
|
||||
std::copy_if(m_nodes.cbegin(), m_nodes.cend(),
|
||||
std::back_inserter(res),
|
||||
@ -190,7 +190,7 @@ QVector<QShaderGraph::Statement> QShaderGraph::createStatements(const QStringLis
|
||||
return res;
|
||||
}();
|
||||
|
||||
const auto enabledEdges = [this, intersectsEnabledLayers] {
|
||||
const QVector<Edge> enabledEdges = [this, intersectsEnabledLayers] {
|
||||
auto res = QVector<Edge>();
|
||||
std::copy_if(m_edges.cbegin(), m_edges.cend(),
|
||||
std::back_inserter(res),
|
||||
@ -200,18 +200,18 @@ QVector<QShaderGraph::Statement> QShaderGraph::createStatements(const QStringLis
|
||||
return res;
|
||||
}();
|
||||
|
||||
const auto idHash = [enabledNodes] {
|
||||
const QHash<QUuid, Statement> idHash = [enabledNodes] {
|
||||
auto nextVarId = 0;
|
||||
auto res = QHash<QUuid, Statement>();
|
||||
for (const auto &node : enabledNodes)
|
||||
for (const QShaderNode &node : enabledNodes)
|
||||
res.insert(node.uuid(), nodeToStatement(node, nextVarId));
|
||||
return res;
|
||||
}();
|
||||
|
||||
auto result = QVector<Statement>();
|
||||
auto currentEdges = enabledEdges;
|
||||
auto currentUuids = [enabledNodes] {
|
||||
const auto inputs = copyOutputNodes(enabledNodes);
|
||||
QVector<Edge> currentEdges = enabledEdges;
|
||||
QVector<QUuid> currentUuids = [enabledNodes] {
|
||||
const QVector<QShaderNode> inputs = copyOutputNodes(enabledNodes);
|
||||
auto res = QVector<QUuid>();
|
||||
std::transform(inputs.cbegin(), inputs.cend(),
|
||||
std::back_inserter(res),
|
||||
@ -226,14 +226,14 @@ QVector<QShaderGraph::Statement> 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<QShaderGraph::Edge> 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<QShaderGraph::Edge> incoming = incomingEdges(currentEdges, nextUuid);
|
||||
if (incoming.isEmpty()) {
|
||||
currentUuids.append(nextUuid);
|
||||
}
|
||||
|
@ -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<int>(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<int>(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());
|
||||
}
|
||||
|
||||
|
@ -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<int>(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<int>(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),
|
||||
|
@ -66,6 +66,11 @@ void QEglFSVivWaylandIntegration::platformInit()
|
||||
mScreenSize.setWidth(width);
|
||||
}
|
||||
|
||||
void QEglFSVivWaylandIntegration::platformDestroy()
|
||||
{
|
||||
wl_display_destroy(mWaylandDisplay);
|
||||
}
|
||||
|
||||
QSize QEglFSVivWaylandIntegration::screenSize() const
|
||||
{
|
||||
return mScreenSize;
|
||||
|
@ -49,6 +49,7 @@ class QEglFSVivWaylandIntegration : public QEglFSDeviceIntegration
|
||||
{
|
||||
public:
|
||||
void platformInit() override;
|
||||
void platformDestroy() override;
|
||||
QSize screenSize() const override;
|
||||
EGLNativeWindowType createNativeWindow(QPlatformWindow *window, const QSize &size, const QSurfaceFormat &format) override;
|
||||
void destroyNativeWindow(EGLNativeWindowType window) override;
|
||||
|
@ -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<QUrl> QWindowsNativeOpenFileDialog::dialogResult() const
|
||||
{
|
||||
QList<QUrl> 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;
|
||||
|
@ -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:
|
||||
|
@ -1581,29 +1581,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);
|
||||
}
|
||||
}
|
||||
@ -1878,7 +1855,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: {
|
||||
|
@ -46,6 +46,7 @@
|
||||
#include "qstyleoption.h"
|
||||
#include "private/qstyle_p.h"
|
||||
#include "private/qguiapplication_p.h"
|
||||
#include <qpa/qplatformtheme.h>
|
||||
#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"
|
||||
|
@ -67,6 +67,9 @@ class QStylePrivate: public QObjectPrivate
|
||||
public:
|
||||
inline QStylePrivate()
|
||||
: layoutSpacingIndex(-1), proxyStyle(nullptr) {}
|
||||
|
||||
static bool useFullScreenForPopup();
|
||||
|
||||
mutable int layoutSpacingIndex;
|
||||
QStyle *proxyStyle;
|
||||
};
|
||||
|
@ -80,6 +80,7 @@
|
||||
#if QT_CONFIG(effects)
|
||||
# include <private/qeffects_p.h>
|
||||
#endif
|
||||
#include <private/qstyle_p.h>
|
||||
#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)
|
||||
|
@ -78,6 +78,7 @@
|
||||
#include <private/qguiapplication_p.h>
|
||||
#include <qpa/qplatformtheme.h>
|
||||
#include <private/qdesktopwidget_p.h>
|
||||
#include <private/qstyle_p.h>
|
||||
|
||||
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<QPointer<QWidget> > QMenuPrivate::calcCausedStack() const
|
||||
|
@ -349,6 +349,7 @@ public:
|
||||
void updateActionRects(const QRect &screen) const;
|
||||
QRect popupGeometry() const;
|
||||
QRect popupGeometry(int screen) const;
|
||||
bool useFullScreenForPopup() const;
|
||||
int getLastVisibleAction() const;
|
||||
|
||||
//selection
|
||||
|
@ -47,6 +47,7 @@ class tst_QUrl : public QObject
|
||||
|
||||
private slots:
|
||||
void initTestCase();
|
||||
void cleanupTestCase();
|
||||
void effectiveTLDs_data();
|
||||
void effectiveTLDs();
|
||||
void getSetCheck();
|
||||
@ -188,6 +189,7 @@ private slots:
|
||||
private:
|
||||
void testThreadingHelper();
|
||||
|
||||
const QString m_currentPath = QDir::currentPath();
|
||||
QTemporaryDir m_tempDir;
|
||||
};
|
||||
|
||||
@ -196,6 +198,12 @@ void tst_QUrl::initTestCase()
|
||||
QVERIFY2(m_tempDir.isValid(), qPrintable(m_tempDir.errorString()));
|
||||
}
|
||||
|
||||
void tst_QUrl::cleanupTestCase()
|
||||
{
|
||||
// Restore working directory changed in fromUserInputWithCwd()
|
||||
QDir::setCurrent(m_currentPath);
|
||||
}
|
||||
|
||||
// Testing get/set functions
|
||||
void tst_QUrl::getSetCheck()
|
||||
{
|
||||
|
@ -40,6 +40,13 @@ struct MyStruct
|
||||
int i;
|
||||
};
|
||||
|
||||
class MyGadget
|
||||
{
|
||||
Q_GADGET
|
||||
public:
|
||||
Q_INVOKABLE MyGadget() {}
|
||||
};
|
||||
|
||||
namespace MyNamespace {
|
||||
// Used in tst_QMetaObject::checkScope
|
||||
class MyClass : public QObject
|
||||
@ -1208,6 +1215,12 @@ void tst_QMetaObject::invokeMetaConstructor()
|
||||
QCOMPARE(obj2->parent(), (QObject*)&obj);
|
||||
QVERIFY(qobject_cast<NamespaceWithConstructibleClass::ConstructibleClass*>(obj2) != 0);
|
||||
}
|
||||
// gadget shouldn't return a valid pointer
|
||||
{
|
||||
QCOMPARE(MyGadget::staticMetaObject.constructorCount(), 1);
|
||||
QTest::ignoreMessage(QtWarningMsg, "QMetaObject::newInstance: type MyGadget does not inherit QObject");
|
||||
QVERIFY(!MyGadget::staticMetaObject.newInstance());
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QMetaObject::invokeTypedefTypes()
|
||||
|
@ -76,11 +76,15 @@ void fill_push_header(const HttpHeader &originalRequest, HttpHeader &promisedReq
|
||||
|
||||
}
|
||||
|
||||
Http2Server::Http2Server(bool h2c, const Http2::RawSettings &ss, const Http2::RawSettings &cs)
|
||||
: serverSettings(ss),
|
||||
expectedClientSettings(cs),
|
||||
clearTextHTTP2(h2c)
|
||||
Http2Server::Http2Server(H2Type type, const Http2::RawSettings &ss, const Http2::RawSettings &cs)
|
||||
: connectionType(type),
|
||||
serverSettings(ss),
|
||||
expectedClientSettings(cs)
|
||||
{
|
||||
#if !QT_CONFIG(ssl)
|
||||
Q_ASSERT(type != H2Type::h2Alpn && type != H2Type::h2Direct);
|
||||
#endif
|
||||
|
||||
responseBody = "<html>\n"
|
||||
"<head>\n"
|
||||
"<title>Sample \"Hello, World\" Application</title>\n"
|
||||
@ -129,15 +133,15 @@ void Http2Server::redirectOpenStream(quint16 port)
|
||||
targetPort = port;
|
||||
}
|
||||
|
||||
bool Http2Server::isClearText() const
|
||||
{
|
||||
return connectionType == H2Type::h2c || connectionType == H2Type::h2cDirect;
|
||||
}
|
||||
|
||||
void Http2Server::startServer()
|
||||
{
|
||||
#ifdef QT_NO_SSL
|
||||
// Let the test fail with timeout.
|
||||
if (!clearTextHTTP2)
|
||||
return;
|
||||
#endif
|
||||
if (listen()) {
|
||||
if (clearTextHTTP2)
|
||||
if (isClearText())
|
||||
authority = QStringLiteral("127.0.0.1:%1").arg(serverPort()).toLatin1();
|
||||
emit serverStarted(serverPort());
|
||||
}
|
||||
@ -146,7 +150,7 @@ void Http2Server::startServer()
|
||||
bool Http2Server::sendProtocolSwitchReply()
|
||||
{
|
||||
Q_ASSERT(socket);
|
||||
Q_ASSERT(clearTextHTTP2 && upgradeProtocol);
|
||||
Q_ASSERT(connectionType == H2Type::h2c);
|
||||
// The first and the last HTTP/1.1 response we send:
|
||||
const char response[] = "HTTP/1.1 101 Switching Protocols\r\n"
|
||||
"Connection: Upgrade\r\n"
|
||||
@ -262,25 +266,28 @@ void Http2Server::sendWINDOW_UPDATE(quint32 streamID, quint32 delta)
|
||||
|
||||
void Http2Server::incomingConnection(qintptr socketDescriptor)
|
||||
{
|
||||
if (clearTextHTTP2) {
|
||||
if (isClearText()) {
|
||||
socket.reset(new QTcpSocket);
|
||||
const bool set = socket->setSocketDescriptor(socketDescriptor);
|
||||
Q_ASSERT(set);
|
||||
// Stop listening:
|
||||
close();
|
||||
upgradeProtocol = true;
|
||||
upgradeProtocol = connectionType == H2Type::h2c;
|
||||
QMetaObject::invokeMethod(this, "connectionEstablished",
|
||||
Qt::QueuedConnection);
|
||||
} else {
|
||||
#ifndef QT_NO_SSL
|
||||
#if QT_CONFIG(ssl)
|
||||
socket.reset(new QSslSocket);
|
||||
QSslSocket *sslSocket = static_cast<QSslSocket *>(socket.data());
|
||||
// Add HTTP2 as supported protocol:
|
||||
auto conf = QSslConfiguration::defaultConfiguration();
|
||||
auto protos = conf.allowedNextProtocols();
|
||||
protos.prepend(QSslConfiguration::ALPNProtocolHTTP2);
|
||||
conf.setAllowedNextProtocols(protos);
|
||||
sslSocket->setSslConfiguration(conf);
|
||||
|
||||
if (connectionType == H2Type::h2Alpn) {
|
||||
// Add HTTP2 as supported protocol:
|
||||
auto conf = QSslConfiguration::defaultConfiguration();
|
||||
auto protos = conf.allowedNextProtocols();
|
||||
protos.prepend(QSslConfiguration::ALPNProtocolHTTP2);
|
||||
conf.setAllowedNextProtocols(protos);
|
||||
sslSocket->setSslConfiguration(conf);
|
||||
}
|
||||
// SSL-related setup ...
|
||||
sslSocket->setPeerVerifyMode(QSslSocket::VerifyNone);
|
||||
sslSocket->setProtocol(QSsl::TlsV1_2OrLater);
|
||||
@ -299,7 +306,7 @@ void Http2Server::incomingConnection(qintptr socketDescriptor)
|
||||
connect(sslSocket, SIGNAL(encrypted()), this, SLOT(connectionEstablished()));
|
||||
sslSocket->startServerEncryption();
|
||||
#else
|
||||
Q_UNREACHABLE();
|
||||
Q_ASSERT(0);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@ -377,7 +384,7 @@ void Http2Server::connectionEstablished()
|
||||
{
|
||||
using namespace Http2;
|
||||
|
||||
if (testingGOAWAY && !clearTextHTTP2)
|
||||
if (testingGOAWAY && !isClearText())
|
||||
return triggerGOAWAYEmulation();
|
||||
|
||||
// For clearTextHTTP2 we first have to respond with 'protocol switch'
|
||||
@ -392,7 +399,7 @@ void Http2Server::connectionEstablished()
|
||||
waitingClientSettings = false;
|
||||
settingsSent = false;
|
||||
|
||||
if (clearTextHTTP2) {
|
||||
if (connectionType == H2Type::h2c) {
|
||||
requestLine.clear();
|
||||
// Now we have to handle HTTP/1.1 request. We use Get/Post in our test,
|
||||
// so set requestType to something unsupported:
|
||||
@ -818,7 +825,7 @@ void Http2Server::sendResponse(quint32 streamID, bool emptyBody)
|
||||
Q_ASSERT(targetPort);
|
||||
header.push_back({":status", "308"});
|
||||
const QString url("%1://localhost:%2/");
|
||||
header.push_back({"location", url.arg(clearTextHTTP2 ? QStringLiteral("http") : QStringLiteral("https"),
|
||||
header.push_back({"location", url.arg(isClearText() ? QStringLiteral("http") : QStringLiteral("https"),
|
||||
QString::number(targetPort)).toLatin1()});
|
||||
|
||||
} else {
|
||||
|
@ -62,21 +62,32 @@ public:
|
||||
Q_DECLARE_PRIVATE(Http11Reply)
|
||||
};
|
||||
|
||||
enum class H2Type {
|
||||
h2Alpn, // Secure connection, ALPN to negotiate h2.
|
||||
h2c, // Clear text with protocol upgrade.
|
||||
h2Direct, // Secure connection, ALPN not supported.
|
||||
h2cDirect, // Clear text direct
|
||||
};
|
||||
|
||||
class Http2Server : public QTcpServer
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
Http2Server(bool clearText, const Http2::RawSettings &serverSettings,
|
||||
|
||||
Http2Server(H2Type type, const Http2::RawSettings &serverSettings,
|
||||
const Http2::RawSettings &clientSettings);
|
||||
|
||||
~Http2Server();
|
||||
|
||||
|
||||
// To be called before server started:
|
||||
void enablePushPromise(bool enabled, const QByteArray &path = QByteArray());
|
||||
void setResponseBody(const QByteArray &body);
|
||||
void emulateGOAWAY(int timeout);
|
||||
void redirectOpenStream(quint16 targetPort);
|
||||
|
||||
bool isClearText() const;
|
||||
|
||||
// Invokables, since we can call them from the main thread,
|
||||
// but server (can) work on its own thread.
|
||||
Q_INVOKABLE void startServer();
|
||||
@ -129,6 +140,7 @@ private:
|
||||
|
||||
QScopedPointer<QAbstractSocket> socket;
|
||||
|
||||
H2Type connectionType = H2Type::h2Alpn;
|
||||
// Connection preface:
|
||||
bool waitingClientPreface = false;
|
||||
bool waitingClientSettings = false;
|
||||
@ -170,7 +182,6 @@ private:
|
||||
quint32 streamRecvWindowSize = Http2::defaultSessionWindowSize;
|
||||
|
||||
QByteArray responseBody;
|
||||
bool clearTextHTTP2 = false;
|
||||
bool pushPromiseEnabled = false;
|
||||
quint32 lastPromisedStream = 0;
|
||||
QByteArray pushPath;
|
||||
|
@ -60,6 +60,9 @@ const bool clearTextHTTP2 = false;
|
||||
const bool clearTextHTTP2 = true;
|
||||
#endif
|
||||
|
||||
Q_DECLARE_METATYPE(H2Type)
|
||||
Q_DECLARE_METATYPE(QNetworkRequest::Attribute)
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class tst_Http2 : public QObject
|
||||
@ -70,6 +73,7 @@ public:
|
||||
~tst_Http2();
|
||||
private slots:
|
||||
// Tests:
|
||||
void singleRequest_data();
|
||||
void singleRequest();
|
||||
void multipleRequests();
|
||||
void flowControlClientSide();
|
||||
@ -101,13 +105,13 @@ private:
|
||||
// small payload.
|
||||
void runEventLoop(int ms = 5000);
|
||||
void stopEventLoop();
|
||||
Http2Server *newServer(const Http2::RawSettings &serverSettings,
|
||||
Http2Server *newServer(const Http2::RawSettings &serverSettings, H2Type connectionType,
|
||||
const Http2::ProtocolParameters &clientSettings = {});
|
||||
// Send a get or post request, depending on a payload (empty or not).
|
||||
void sendRequest(int streamNumber,
|
||||
QNetworkRequest::Priority priority = QNetworkRequest::NormalPriority,
|
||||
const QByteArray &payload = QByteArray());
|
||||
QUrl requestUrl() const;
|
||||
QUrl requestUrl(H2Type connnectionType) const;
|
||||
|
||||
quint16 serverPort = 0;
|
||||
QThread *workerThread = nullptr;
|
||||
@ -144,6 +148,11 @@ struct ServerDeleter
|
||||
|
||||
using ServerPtr = QScopedPointer<Http2Server, ServerDeleter>;
|
||||
|
||||
H2Type defaultConnectionType()
|
||||
{
|
||||
return clearTextHTTP2 ? H2Type::h2c : H2Type::h2Alpn;
|
||||
}
|
||||
|
||||
} // unnamed namespace
|
||||
|
||||
tst_Http2::tst_Http2()
|
||||
@ -165,25 +174,59 @@ tst_Http2::~tst_Http2()
|
||||
}
|
||||
}
|
||||
|
||||
void tst_Http2::singleRequest_data()
|
||||
{
|
||||
QTest::addColumn<QNetworkRequest::Attribute>("h2Attribute");
|
||||
QTest::addColumn<H2Type>("connectionType");
|
||||
|
||||
// 'Clear text' that should always work, either via the protocol upgrade
|
||||
// or as direct.
|
||||
QTest::addRow("h2c-upgrade") << QNetworkRequest::HTTP2AllowedAttribute << H2Type::h2c;
|
||||
QTest::addRow("h2c-direct") << QNetworkRequest::Http2DirectAttribute << H2Type::h2cDirect;
|
||||
|
||||
if (!clearTextHTTP2) {
|
||||
// Qt with TLS where TLS-backend supports ALPN.
|
||||
QTest::addRow("h2-ALPN") << QNetworkRequest::HTTP2AllowedAttribute << H2Type::h2Alpn;
|
||||
}
|
||||
|
||||
#if QT_CONFIG(ssl)
|
||||
QTest::addRow("h2-direct") << QNetworkRequest::Http2DirectAttribute << H2Type::h2Direct;
|
||||
#endif
|
||||
}
|
||||
|
||||
void tst_Http2::singleRequest()
|
||||
{
|
||||
clearHTTP2State();
|
||||
|
||||
#if QT_CONFIG(securetransport)
|
||||
// Normally on macOS we use plain text only for SecureTransport
|
||||
// does not support ALPN on the server side. With 'direct encrytped'
|
||||
// we have to use TLS sockets (== private key) and thus suppress a
|
||||
// keychain UI asking for permission to use a private key.
|
||||
// Our CI has this, but somebody testing locally - will have a problem.
|
||||
qputenv("QT_SSL_USE_TEMPORARY_KEYCHAIN", QByteArray("1"));
|
||||
auto envRollback = qScopeGuard([](){
|
||||
qunsetenv("QT_SSL_USE_TEMPORARY_KEYCHAIN");
|
||||
});
|
||||
#endif
|
||||
|
||||
serverPort = 0;
|
||||
nRequests = 1;
|
||||
|
||||
ServerPtr srv(newServer(defaultServerSettings));
|
||||
QFETCH(const H2Type, connectionType);
|
||||
ServerPtr srv(newServer(defaultServerSettings, connectionType));
|
||||
|
||||
QMetaObject::invokeMethod(srv.data(), "startServer", Qt::QueuedConnection);
|
||||
runEventLoop();
|
||||
|
||||
QVERIFY(serverPort != 0);
|
||||
|
||||
auto url = requestUrl();
|
||||
auto url = requestUrl(connectionType);
|
||||
url.setPath("/index.html");
|
||||
|
||||
QNetworkRequest request(url);
|
||||
request.setAttribute(QNetworkRequest::HTTP2AllowedAttribute, QVariant(true));
|
||||
QFETCH(const QNetworkRequest::Attribute, h2Attribute);
|
||||
request.setAttribute(h2Attribute, QVariant(true));
|
||||
|
||||
auto reply = manager.get(request);
|
||||
connect(reply, &QNetworkReply::finished, this, &tst_Http2::replyFinished);
|
||||
@ -208,7 +251,7 @@ void tst_Http2::multipleRequests()
|
||||
serverPort = 0;
|
||||
nRequests = 10;
|
||||
|
||||
ServerPtr srv(newServer(defaultServerSettings));
|
||||
ServerPtr srv(newServer(defaultServerSettings, defaultConnectionType()));
|
||||
|
||||
QMetaObject::invokeMethod(srv.data(), "startServer", Qt::QueuedConnection);
|
||||
|
||||
@ -259,7 +302,7 @@ void tst_Http2::flowControlClientSide()
|
||||
manager.setProperty(Http2::http2ParametersPropertyName, QVariant::fromValue(params));
|
||||
|
||||
const Http2::RawSettings serverSettings = {{Settings::MAX_CONCURRENT_STREAMS_ID, quint32(3)}};
|
||||
ServerPtr srv(newServer(serverSettings, params));
|
||||
ServerPtr srv(newServer(serverSettings, defaultConnectionType(), params));
|
||||
|
||||
|
||||
const QByteArray respond(int(Http2::defaultSessionWindowSize * 10), 'x');
|
||||
@ -301,7 +344,7 @@ void tst_Http2::flowControlServerSide()
|
||||
|
||||
const Http2::RawSettings serverSettings = {{Settings::MAX_CONCURRENT_STREAMS_ID, 7}};
|
||||
|
||||
ServerPtr srv(newServer(serverSettings));
|
||||
ServerPtr srv(newServer(serverSettings, defaultConnectionType()));
|
||||
|
||||
const QByteArray payload(int(Http2::defaultSessionWindowSize * 500), 'x');
|
||||
|
||||
@ -336,7 +379,7 @@ void tst_Http2::pushPromise()
|
||||
params.settingsFrameData[Settings::ENABLE_PUSH_ID] = 1;
|
||||
manager.setProperty(Http2::http2ParametersPropertyName, QVariant::fromValue(params));
|
||||
|
||||
ServerPtr srv(newServer(defaultServerSettings, params));
|
||||
ServerPtr srv(newServer(defaultServerSettings, defaultConnectionType(), params));
|
||||
srv->enablePushPromise(true, QByteArray("/script.js"));
|
||||
|
||||
QMetaObject::invokeMethod(srv.data(), "startServer", Qt::QueuedConnection);
|
||||
@ -344,7 +387,7 @@ void tst_Http2::pushPromise()
|
||||
|
||||
QVERIFY(serverPort != 0);
|
||||
|
||||
auto url = requestUrl();
|
||||
auto url = requestUrl(defaultConnectionType());
|
||||
url.setPath("/index.html");
|
||||
|
||||
QNetworkRequest request(url);
|
||||
@ -410,14 +453,14 @@ void tst_Http2::goaway()
|
||||
serverPort = 0;
|
||||
nRequests = 3;
|
||||
|
||||
ServerPtr srv(newServer(defaultServerSettings));
|
||||
ServerPtr srv(newServer(defaultServerSettings, defaultConnectionType()));
|
||||
srv->emulateGOAWAY(responseTimeoutMS);
|
||||
QMetaObject::invokeMethod(srv.data(), "startServer", Qt::QueuedConnection);
|
||||
runEventLoop();
|
||||
|
||||
QVERIFY(serverPort != 0);
|
||||
|
||||
auto url = requestUrl();
|
||||
auto url = requestUrl(defaultConnectionType());
|
||||
// We have to store these replies, so that we can check errors later.
|
||||
std::vector<QNetworkReply *> replies(nRequests);
|
||||
for (int i = 0; i < nRequests; ++i) {
|
||||
@ -457,7 +500,7 @@ void tst_Http2::earlyResponse()
|
||||
serverPort = 0;
|
||||
nRequests = 1;
|
||||
|
||||
ServerPtr targetServer(newServer(defaultServerSettings));
|
||||
ServerPtr targetServer(newServer(defaultServerSettings, defaultConnectionType()));
|
||||
|
||||
QMetaObject::invokeMethod(targetServer.data(), "startServer", Qt::QueuedConnection);
|
||||
runEventLoop();
|
||||
@ -467,7 +510,7 @@ void tst_Http2::earlyResponse()
|
||||
const quint16 targetPort = serverPort;
|
||||
serverPort = 0;
|
||||
|
||||
ServerPtr redirector(newServer(defaultServerSettings));
|
||||
ServerPtr redirector(newServer(defaultServerSettings, defaultConnectionType()));
|
||||
redirector->redirectOpenStream(targetPort);
|
||||
|
||||
QMetaObject::invokeMethod(redirector.data(), "startServer", Qt::QueuedConnection);
|
||||
@ -507,11 +550,11 @@ void tst_Http2::stopEventLoop()
|
||||
eventLoop.exitLoop();
|
||||
}
|
||||
|
||||
Http2Server *tst_Http2::newServer(const Http2::RawSettings &serverSettings,
|
||||
Http2Server *tst_Http2::newServer(const Http2::RawSettings &serverSettings, H2Type connectionType,
|
||||
const Http2::ProtocolParameters &clientSettings)
|
||||
{
|
||||
using namespace Http2;
|
||||
auto srv = new Http2Server(clearTextHTTP2, serverSettings,
|
||||
auto srv = new Http2Server(connectionType, serverSettings,
|
||||
clientSettings.settingsFrameData);
|
||||
|
||||
using Srv = Http2Server;
|
||||
@ -536,7 +579,7 @@ void tst_Http2::sendRequest(int streamNumber,
|
||||
QNetworkRequest::Priority priority,
|
||||
const QByteArray &payload)
|
||||
{
|
||||
auto url = requestUrl();
|
||||
auto url = requestUrl(defaultConnectionType());
|
||||
url.setPath(QString("/stream%1.html").arg(streamNumber));
|
||||
|
||||
QNetworkRequest request(url);
|
||||
@ -555,10 +598,24 @@ void tst_Http2::sendRequest(int streamNumber,
|
||||
connect(reply, &QNetworkReply::finished, this, &tst_Http2::replyFinished);
|
||||
}
|
||||
|
||||
QUrl tst_Http2::requestUrl() const
|
||||
QUrl tst_Http2::requestUrl(H2Type connectionType) const
|
||||
{
|
||||
#if !QT_CONFIG(ssl)
|
||||
Q_ASSERT(connectionType != H2Type::h2Alpn && connectionType != H2Type::h2Direct);
|
||||
#endif
|
||||
static auto url = QUrl(QLatin1String(clearTextHTTP2 ? "http://127.0.0.1" : "https://127.0.0.1"));
|
||||
url.setPort(serverPort);
|
||||
// Clear text may mean no-TLS-at-all or crappy-TLS-without-ALPN.
|
||||
switch (connectionType) {
|
||||
case H2Type::h2Alpn:
|
||||
case H2Type::h2Direct:
|
||||
url.setScheme(QStringLiteral("https"));
|
||||
break;
|
||||
case H2Type::h2c:
|
||||
case H2Type::h2cDirect:
|
||||
url.setScheme(QStringLiteral("http"));
|
||||
break;
|
||||
}
|
||||
|
||||
return url;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user