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
|
#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 sourceFile(source);
|
||||||
QFile targetFile(target);
|
QFile targetFile(target);
|
||||||
@ -260,35 +261,32 @@ static int installFile(const QString &source, const QString &target, bool exe =
|
|||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QFileDevice::Permissions targetPermissions = preservePermissions
|
||||||
|
? sourceFile.permissions()
|
||||||
|
: (QFileDevice::ReadOwner | QFileDevice::WriteOwner
|
||||||
|
| QFileDevice::ReadUser | QFileDevice::WriteUser
|
||||||
|
| QFileDevice::ReadGroup | QFileDevice::ReadOther);
|
||||||
if (exe) {
|
if (exe) {
|
||||||
if (!targetFile.setPermissions(sourceFile.permissions() | QFileDevice::ExeOwner | QFileDevice::ExeUser |
|
targetPermissions |= QFileDevice::ExeOwner | QFileDevice::ExeUser |
|
||||||
QFileDevice::ExeGroup | QFileDevice::ExeOther)) {
|
QFileDevice::ExeGroup | QFileDevice::ExeOther;
|
||||||
fprintf(stderr, "Error setting execute permissions on %s: %s\n",
|
}
|
||||||
|
if (!targetFile.setPermissions(targetPermissions)) {
|
||||||
|
fprintf(stderr, "Error setting permissions on %s: %s\n",
|
||||||
qPrintable(target), qPrintable(targetFile.errorString()));
|
qPrintable(target), qPrintable(targetFile.errorString()));
|
||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Copy file times
|
// Copy file times
|
||||||
QString error;
|
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)) {
|
if (!IoUtils::touchFile(target, sourceFile.fileName(), &error)) {
|
||||||
fprintf(stderr, "%s", qPrintable(error));
|
fprintf(stderr, "%s", qPrintable(error));
|
||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
#ifdef Q_OS_WIN
|
|
||||||
if (readOnly)
|
|
||||||
targetFile.setPermissions(permissions);
|
|
||||||
#endif
|
|
||||||
return 0;
|
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);
|
QFileInfo fi(source);
|
||||||
if (false) {
|
if (false) {
|
||||||
@ -308,18 +306,18 @@ static int installFileOrDirectory(const QString &source, const QString &target)
|
|||||||
} else if (fi.isDir()) {
|
} else if (fi.isDir()) {
|
||||||
QDir::current().mkpath(target);
|
QDir::current().mkpath(target);
|
||||||
|
|
||||||
QDirIterator it(source, QDir::AllEntries | QDir::NoDotAndDotDot);
|
QDirIterator it(source, QDir::AllEntries | QDir::NoDotAndDotDot | QDir::Hidden);
|
||||||
while (it.hasNext()) {
|
while (it.hasNext()) {
|
||||||
it.next();
|
it.next();
|
||||||
const QFileInfo &entry = it.fileInfo();
|
const QFileInfo &entry = it.fileInfo();
|
||||||
const QString &entryTarget = target + QDir::separator() + entry.fileName();
|
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)
|
if (recursionResult != 0)
|
||||||
return recursionResult;
|
return recursionResult;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const int fileCopyResult = installFile(source, target);
|
const int fileCopyResult = installFile(source, target, /*exe*/ false, preservePermissions);
|
||||||
if (fileCopyResult != 0)
|
if (fileCopyResult != 0)
|
||||||
return fileCopyResult;
|
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)
|
CBOR_INLINE_API CborError cbor_encode_half_float(CborEncoder *encoder, const void *value)
|
||||||
{ return cbor_encode_floating_point(encoder, CborHalfFloatType, 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)
|
CBOR_INLINE_API CborError cbor_encode_float(CborEncoder *encoder, float value)
|
||||||
{ return cbor_encode_floating_point(encoder, CborFloatType, &value); }
|
{ return cbor_encode_floating_point(encoder, CborFloatType, &value); }
|
||||||
CBOR_INLINE_API CborError cbor_encode_double(CborEncoder *encoder, double 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 */
|
/* Floating point */
|
||||||
CBOR_INLINE_API bool cbor_value_is_half_float(const CborValue *value)
|
CBOR_INLINE_API bool cbor_value_is_half_float(const CborValue *value)
|
||||||
{ return value->type == CborHalfFloatType; }
|
{ 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)
|
CBOR_INLINE_API CborError cbor_value_get_half_float(const CborValue *value, void *result)
|
||||||
{
|
{
|
||||||
assert(cbor_value_is_half_float(value));
|
assert(cbor_value_is_half_float(value));
|
||||||
assert((value->flags & CborIteratorFlag_IntegerValueTooLarge) == 0);
|
assert((value->flags & CborIteratorFlag_IntegerValueTooLarge) == 0);
|
||||||
|
|
||||||
/* size has been computed already */
|
/* size has already been computed */
|
||||||
memcpy(result, &value->extra, sizeof(value->extra));
|
memcpy(result, &value->extra, sizeof(value->extra));
|
||||||
return CborNoError;
|
return CborNoError;
|
||||||
}
|
}
|
||||||
|
24
src/3rdparty/tinycbor/src/cborencoder.c
vendored
24
src/3rdparty/tinycbor/src/cborencoder.c
vendored
@ -76,7 +76,7 @@
|
|||||||
* \code
|
* \code
|
||||||
* uint8_t buf[16];
|
* uint8_t buf[16];
|
||||||
* CborEncoder encoder, mapEncoder;
|
* 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_encoder_create_map(&encoder, &mapEncoder, 1);
|
||||||
* cbor_encode_text_stringz(&mapEncoder, "foo");
|
* cbor_encode_text_stringz(&mapEncoder, "foo");
|
||||||
* cbor_encode_boolean(&mapEncoder, some_value);
|
* cbor_encode_boolean(&mapEncoder, some_value);
|
||||||
@ -115,7 +115,7 @@
|
|||||||
* uint8_t buf[16];
|
* uint8_t buf[16];
|
||||||
* CborError err;
|
* CborError err;
|
||||||
* CborEncoder encoder, mapEncoder;
|
* 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);
|
* err = cbor_encoder_create_map(&encoder, &mapEncoder, 1);
|
||||||
* if (!err)
|
* if (!err)
|
||||||
* return err;
|
* return err;
|
||||||
@ -155,7 +155,7 @@
|
|||||||
* goto error;
|
* goto error;
|
||||||
* buf = nbuf;
|
* buf = nbuf;
|
||||||
*
|
*
|
||||||
* cbor_encoder_init(&encoder, &buf, size, 0);
|
* cbor_encoder_init(&encoder, buf, size, 0);
|
||||||
* err = cbor_encoder_create_array(&encoder, &arrayEncoder, n);
|
* err = cbor_encoder_create_array(&encoder, &arrayEncoder, n);
|
||||||
* cbor_assert(err); // can't fail, the buffer is always big enough
|
* 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
|
* 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.
|
* 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)
|
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()
|
* \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)
|
* \fn CborError cbor_encode_float(CborEncoder *encoder, float value)
|
||||||
*
|
*
|
||||||
* Appends the IEEE 754 single-precision (32-bit) floating point value \a value
|
* Appends the IEEE 754 single-precision (32-bit) floating point value \a value
|
||||||
* to the CBOR stream provided by \a encoder.
|
* 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
|
* Appends the IEEE 754 double-precision (64-bit) floating point value \a value
|
||||||
* to the CBOR stream provided by \a encoder.
|
* 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
|
* floating point, this function takes a \c{void *} as a parameter for the
|
||||||
* storage area, which must be at least 16 bits wide.
|
* 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_ntohs __builtin_bswap16
|
||||||
# define cbor_htons __builtin_bswap16
|
# define cbor_htons __builtin_bswap16
|
||||||
# else
|
# 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
|
# define cbor_htons cbor_ntohs
|
||||||
# endif
|
# endif
|
||||||
# else
|
# 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));
|
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()
|
void addColumns()
|
||||||
{
|
{
|
||||||
QTest::addColumn<QByteArray>("output");
|
QTest::addColumn<QByteArray>("output");
|
||||||
|
119
src/3rdparty/tinycbor/tests/encoder/tst_encoder.cpp
vendored
119
src/3rdparty/tinycbor/tests/encoder/tst_encoder.cpp
vendored
@ -41,6 +41,13 @@ class tst_Encoder : public QObject
|
|||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
private slots:
|
private slots:
|
||||||
|
void floatAsHalfFloat_data();
|
||||||
|
void floatAsHalfFloat();
|
||||||
|
void halfFloat_data();
|
||||||
|
void halfFloat();
|
||||||
|
void floatAsHalfFloatCloseToZero_data();
|
||||||
|
void floatAsHalfFloatCloseToZero();
|
||||||
|
void floatAsHalfFloatNaN();
|
||||||
void fixed_data();
|
void fixed_data();
|
||||||
void fixed();
|
void fixed();
|
||||||
void strings_data();
|
void strings_data();
|
||||||
@ -178,21 +185,127 @@ CborError encodeVariant(CborEncoder *encoder, const QVariant &v)
|
|||||||
return CborErrorUnknownType;
|
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());
|
uint8_t *bufptr = reinterpret_cast<quint8 *>(buffer.data());
|
||||||
CborEncoder encoder;
|
CborEncoder encoder;
|
||||||
cbor_encoder_init(&encoder, bufptr, buffer.length(), 0);
|
cbor_encoder_init(&encoder, bufptr, buffer.length(), 0);
|
||||||
|
|
||||||
QCOMPARE(encodeVariant(&encoder, input), CborNoError);
|
error = fn_under_test(&encoder, input);
|
||||||
|
|
||||||
|
if (error == CborNoError) {
|
||||||
QCOMPARE(encoder.remaining, size_t(1));
|
QCOMPARE(encoder.remaining, size_t(1));
|
||||||
QCOMPARE(cbor_encoder_get_extra_bytes_needed(&encoder), size_t(0));
|
QCOMPARE(cbor_encoder_get_extra_bytes_needed(&encoder), size_t(0));
|
||||||
|
|
||||||
buffer.resize(int(cbor_encoder_get_buffer_size(&encoder, bufptr)));
|
buffer.resize(int(cbor_encoder_get_buffer_size(&encoder, bufptr)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <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);
|
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()
|
void tst_Encoder::fixed_data()
|
||||||
{
|
{
|
||||||
addColumns();
|
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
|
** Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
** of this software and associated documentation files (the "Software"), to deal
|
** of this software and associated documentation files (the "Software"), to deal
|
||||||
@ -23,11 +23,22 @@
|
|||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
#define _XOPEN_SOURCE 700
|
#define _XOPEN_SOURCE 700
|
||||||
|
#define _DARWIN_C_SOURCE 1 /* need MAP_ANON */
|
||||||
#include <QtTest>
|
#include <QtTest>
|
||||||
#include "cbor.h"
|
#include "cbor.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdarg.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 {
|
namespace QTest {
|
||||||
template<> char *toString<CborError>(const CborError &err)
|
template<> char *toString<CborError>(const CborError &err)
|
||||||
{
|
{
|
||||||
@ -44,6 +55,8 @@ private slots:
|
|||||||
// parsing API
|
// parsing API
|
||||||
void integers_data();
|
void integers_data();
|
||||||
void integers();
|
void integers();
|
||||||
|
void halfFloat_data();
|
||||||
|
void halfFloat();
|
||||||
void fixed_data();
|
void fixed_data();
|
||||||
void fixed();
|
void fixed();
|
||||||
void strings_data();
|
void strings_data();
|
||||||
@ -105,6 +118,100 @@ private slots:
|
|||||||
void recursionLimit();
|
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, ...)
|
static CborError qstring_printf(void *out, const char *fmt, ...)
|
||||||
{
|
{
|
||||||
auto str = static_cast<QString *>(out);
|
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)
|
void compareOne_real(const QByteArray &data, const QString &expected, int line, int n = -1)
|
||||||
{
|
{
|
||||||
compareFailed = true;
|
compareFailed = true;
|
||||||
CborParser parser;
|
ParserWrapper w;
|
||||||
CborValue first;
|
CborError err = w.init(data);
|
||||||
CborError err = cbor_parser_init(reinterpret_cast<const quint8 *>(data.constData()), data.length(), 0, &parser, &first);
|
|
||||||
QVERIFY2(!err, QByteArray::number(line) + ": Got error \"" + cbor_error_string(err) + "\"");
|
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;
|
size_t len;
|
||||||
if (n >= 0) {
|
if (n >= 0) {
|
||||||
QVERIFY(cbor_value_is_length_known(&first));
|
QVERIFY(cbor_value_is_length_known(&w.first));
|
||||||
QCOMPARE(cbor_value_get_array_length(&first, &len), CborNoError);
|
QCOMPARE(cbor_value_get_array_length(&w.first, &len), CborNoError);
|
||||||
QCOMPARE(len, size_t(len));
|
QCOMPARE(len, size_t(len));
|
||||||
} else {
|
} else {
|
||||||
QVERIFY(!cbor_value_is_length_known(&first));
|
QVERIFY(!cbor_value_is_length_known(&w.first));
|
||||||
QCOMPARE(cbor_value_get_array_length(&first, &len), CborErrorUnknownLength);
|
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;
|
size_t len;
|
||||||
if (n >= 0) {
|
if (n >= 0) {
|
||||||
QVERIFY(cbor_value_is_length_known(&first));
|
QVERIFY(cbor_value_is_length_known(&w.first));
|
||||||
QCOMPARE(cbor_value_get_map_length(&first, &len), CborNoError);
|
QCOMPARE(cbor_value_get_map_length(&w.first, &len), CborNoError);
|
||||||
QCOMPARE(len, size_t(len));
|
QCOMPARE(len, size_t(len));
|
||||||
} else {
|
} else {
|
||||||
QVERIFY(!cbor_value_is_length_known(&first));
|
QVERIFY(!cbor_value_is_length_known(&w.first));
|
||||||
QCOMPARE(cbor_value_get_map_length(&first, &len), CborErrorUnknownLength);
|
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;
|
size_t len;
|
||||||
QCOMPARE(cbor_value_calculate_string_length(&first, &len), CborNoError);
|
QCOMPARE(cbor_value_calculate_string_length(&w.first, &len), CborNoError);
|
||||||
if (cbor_value_is_length_known(&first)) {
|
if (cbor_value_is_length_known(&w.first)) {
|
||||||
size_t len2;
|
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);
|
QCOMPARE(len2, len);
|
||||||
} else {
|
} 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;
|
QString decoded;
|
||||||
err = parseOne(&first, &decoded);
|
err = parseOne(&w.first, &decoded);
|
||||||
QVERIFY2(!err, QByteArray::number(line) + ": Got error \"" + cbor_error_string(err) +
|
QVERIFY2(!err, QByteArray::number(line) + ": Got error \"" + cbor_error_string(err) +
|
||||||
"\"; decoded stream:\n" + decoded.toLatin1());
|
"\"; decoded stream:\n" + decoded.toLatin1());
|
||||||
QCOMPARE(decoded, expected);
|
QCOMPARE(decoded, expected);
|
||||||
@ -215,7 +321,7 @@ void compareOne_real(const QByteArray &data, const QString &expected, int line,
|
|||||||
QCOMPARE(err2, err);
|
QCOMPARE(err2, err);
|
||||||
|
|
||||||
// check that we consumed everything
|
// 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;
|
compareFailed = false;
|
||||||
}
|
}
|
||||||
@ -237,39 +343,112 @@ void tst_Parser::integers()
|
|||||||
QFETCH(qint64, expectedValue);
|
QFETCH(qint64, expectedValue);
|
||||||
QFETCH(bool, inInt64Range);
|
QFETCH(bool, inInt64Range);
|
||||||
|
|
||||||
CborParser parser;
|
ParserWrapper w;
|
||||||
CborValue first;
|
CborError err = w.init(data);
|
||||||
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) + "\"");
|
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;
|
uint64_t raw;
|
||||||
cbor_value_get_raw_integer(&first, &raw);
|
cbor_value_get_raw_integer(&w.first, &raw);
|
||||||
QCOMPARE(quint64(raw), expectedRaw);
|
QCOMPARE(quint64(raw), expectedRaw);
|
||||||
|
|
||||||
if (isNegative) {
|
if (isNegative) {
|
||||||
QVERIFY(cbor_value_is_negative_integer(&first));
|
QVERIFY(cbor_value_is_negative_integer(&w.first));
|
||||||
QVERIFY(!cbor_value_is_unsigned_integer(&first));
|
QVERIFY(!cbor_value_is_unsigned_integer(&w.first));
|
||||||
} else {
|
} else {
|
||||||
QVERIFY(!cbor_value_is_negative_integer(&first));
|
QVERIFY(!cbor_value_is_negative_integer(&w.first));
|
||||||
QVERIFY(cbor_value_is_unsigned_integer(&first));
|
QVERIFY(cbor_value_is_unsigned_integer(&w.first));
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t value;
|
int64_t value;
|
||||||
if (inInt64Range) {
|
if (inInt64Range) {
|
||||||
cbor_value_get_int64(&first, &value);
|
cbor_value_get_int64(&w.first, &value);
|
||||||
QCOMPARE(qint64(value), expectedValue);
|
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);
|
QCOMPARE(err, inInt64Range ? CborNoError : CborErrorDataTooLarge);
|
||||||
|
|
||||||
int ivalue;
|
int ivalue;
|
||||||
bool inIntRange = inInt64Range && (expectedValue == int(expectedValue));
|
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);
|
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()
|
void tst_Parser::fixed_data()
|
||||||
{
|
{
|
||||||
addColumns();
|
addColumns();
|
||||||
@ -678,14 +857,13 @@ void tst_Parser::chunkedString_data()
|
|||||||
static void chunkedStringTest(const QByteArray &data, const QString &concatenated,
|
static void chunkedStringTest(const QByteArray &data, const QString &concatenated,
|
||||||
QStringList &chunks, CborType ourType)
|
QStringList &chunks, CborType ourType)
|
||||||
{
|
{
|
||||||
CborParser parser;
|
ParserWrapper w;
|
||||||
CborValue first;
|
CborError err = w.init(data);
|
||||||
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) + "\"");
|
QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\"");
|
||||||
|
|
||||||
CborValue value;
|
CborValue value;
|
||||||
QVERIFY(cbor_value_is_array(&first));
|
QVERIFY(cbor_value_is_array(&w.first));
|
||||||
err = cbor_value_enter_container(&first, &value);
|
err = cbor_value_enter_container(&w.first, &value);
|
||||||
QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\"");
|
QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\"");
|
||||||
QVERIFY(cbor_value_is_byte_string(&value) || cbor_value_is_text_string(&value));
|
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
|
// confirm EOF
|
||||||
QVERIFY(cbor_value_at_end(&value));
|
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) + "\"");
|
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()
|
void tst_Parser::chunkedString()
|
||||||
@ -840,18 +1018,17 @@ void tst_Parser::stringLength()
|
|||||||
QFETCH(QByteArray, data);
|
QFETCH(QByteArray, data);
|
||||||
QFETCH(int, expected);
|
QFETCH(int, expected);
|
||||||
|
|
||||||
CborParser parser;
|
ParserWrapper w;
|
||||||
CborValue value;
|
CborError err = w.init(data);
|
||||||
CborError err = cbor_parser_init(reinterpret_cast<const quint8 *>(data.constData()), data.length(), 0, &parser, &value);
|
|
||||||
QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\"");
|
QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\"");
|
||||||
|
|
||||||
size_t result;
|
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) + "\"");
|
QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\"");
|
||||||
QCOMPARE(result, size_t(expected));
|
QCOMPARE(result, size_t(expected));
|
||||||
|
|
||||||
if (cbor_value_is_length_known(&value)) {
|
if (cbor_value_is_length_known(&w.first)) {
|
||||||
QCOMPARE(cbor_value_get_string_length(&value, &result), CborNoError);
|
QCOMPARE(cbor_value_get_string_length(&w.first, &result), CborNoError);
|
||||||
QCOMPARE(result, size_t(expected));
|
QCOMPARE(result, size_t(expected));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -935,25 +1112,24 @@ void compareOneString(const QByteArray &data, const QString &string, bool expect
|
|||||||
{
|
{
|
||||||
compareFailed = true;
|
compareFailed = true;
|
||||||
|
|
||||||
CborParser parser;
|
ParserWrapper w;
|
||||||
CborValue value;
|
CborError err = w.init(data);
|
||||||
CborError err = cbor_parser_init(reinterpret_cast<const quint8 *>(data.constData()), data.length(), 0, &parser, &value);
|
|
||||||
QVERIFY2(!err, QByteArray::number(line) + ": Got error \"" + cbor_error_string(err) + "\"");
|
QVERIFY2(!err, QByteArray::number(line) + ": Got error \"" + cbor_error_string(err) + "\"");
|
||||||
|
|
||||||
bool result;
|
bool result;
|
||||||
QByteArray bastring = string.toUtf8();
|
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) + "\"");
|
QVERIFY2(!err, QByteArray::number(line) + ": Got error \"" + cbor_error_string(err) + "\"");
|
||||||
QCOMPARE(result, expected);
|
QCOMPARE(result, expected);
|
||||||
|
|
||||||
if (expected) {
|
if (expected) {
|
||||||
size_t len;
|
size_t len;
|
||||||
cbor_value_skip_tag(&value);
|
cbor_value_skip_tag(&w.first);
|
||||||
if (cbor_value_is_length_known(&value)) {
|
if (cbor_value_is_length_known(&w.first)) {
|
||||||
QCOMPARE(cbor_value_get_string_length(&value, &len), CborNoError);
|
QCOMPARE(cbor_value_get_string_length(&w.first, &len), CborNoError);
|
||||||
QCOMPARE(int(len), bastring.size());
|
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());
|
QCOMPARE(int(len), bastring.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1042,13 +1218,12 @@ void tst_Parser::mapFind()
|
|||||||
QFETCH(QByteArray, data);
|
QFETCH(QByteArray, data);
|
||||||
QFETCH(bool, expected);
|
QFETCH(bool, expected);
|
||||||
|
|
||||||
CborParser parser;
|
ParserWrapper w;
|
||||||
CborValue value;
|
CborError err = w.init(data);
|
||||||
CborError err = cbor_parser_init(reinterpret_cast<const quint8 *>(data.constData()), data.length(), 0, &parser, &value);
|
|
||||||
QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\"");
|
QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\"");
|
||||||
|
|
||||||
CborValue element;
|
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) + "\"");
|
QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\"");
|
||||||
|
|
||||||
if (expected) {
|
if (expected) {
|
||||||
@ -1119,13 +1294,12 @@ void tst_Parser::checkedIntegers()
|
|||||||
QFETCH(QVariant, result);
|
QFETCH(QVariant, result);
|
||||||
int64_t expected = result.toLongLong();
|
int64_t expected = result.toLongLong();
|
||||||
|
|
||||||
CborParser parser;
|
ParserWrapper w;
|
||||||
CborValue value;
|
CborError err = w.init(data);
|
||||||
CborError err = cbor_parser_init(reinterpret_cast<const quint8 *>(data.constData()), data.length(), 0, &parser, &value);
|
|
||||||
QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\"");
|
QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\"");
|
||||||
|
|
||||||
int64_t v;
|
int64_t v;
|
||||||
err = cbor_value_get_int64_checked(&value, &v);
|
err = cbor_value_get_int64_checked(&w.first, &v);
|
||||||
if (result.isNull()) {
|
if (result.isNull()) {
|
||||||
QCOMPARE(err, CborErrorDataTooLarge);
|
QCOMPARE(err, CborErrorDataTooLarge);
|
||||||
} else {
|
} else {
|
||||||
@ -1133,7 +1307,7 @@ void tst_Parser::checkedIntegers()
|
|||||||
}
|
}
|
||||||
|
|
||||||
int v2;
|
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()) {
|
if (result.isNull() || expected < std::numeric_limits<int>::min() || expected > std::numeric_limits<int>::max()) {
|
||||||
QCOMPARE(err, CborErrorDataTooLarge);
|
QCOMPARE(err, CborErrorDataTooLarge);
|
||||||
} else {
|
} else {
|
||||||
@ -1154,14 +1328,13 @@ void tst_Parser::validation()
|
|||||||
QFETCH(CborError, expectedError);
|
QFETCH(CborError, expectedError);
|
||||||
|
|
||||||
QString decoded;
|
QString decoded;
|
||||||
CborParser parser;
|
ParserWrapper w;
|
||||||
CborValue first;
|
CborError err = w.init(data, uint32_t(flags));
|
||||||
CborError err = cbor_parser_init(reinterpret_cast<const quint8 *>(data.constData()), data.length(), flags, &parser, &first);
|
|
||||||
QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\"");
|
QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\"");
|
||||||
|
|
||||||
CborError err2 = cbor_value_validate_basic(&first);
|
CborError err2 = cbor_value_validate_basic(&w.first);
|
||||||
CborError err3 = cbor_value_validate(&first, CborValidateBasic);
|
CborError err3 = cbor_value_validate(&w.first, CborValidateBasic);
|
||||||
err = parseOne(&first, &decoded);
|
err = parseOne(&w.first, &decoded);
|
||||||
QCOMPARE(err, expectedError);
|
QCOMPARE(err, expectedError);
|
||||||
if (!QByteArray(QTest::currentDataTag()).contains("utf8")) {
|
if (!QByteArray(QTest::currentDataTag()).contains("utf8")) {
|
||||||
QCOMPARE(err2, expectedError);
|
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;
|
QTest::newRow("overlong-_stringx2-0*8") << raw("\x7f\x60\x7b\0\0\0\0\0\0\0\0\xff") << int(CborValidateShortestNumbers) << CborErrorOverlongEncoding;
|
||||||
|
|
||||||
// strict mode
|
// strict mode
|
||||||
QTest::newRow("invalid-utf8-1char") << raw("\x61\x80") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString;
|
// UTF-8 sequences with invalid continuation bytes
|
||||||
QTest::newRow("invalid-utf8-2chars-1") << raw("\x62\xc2\xc0") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString;
|
QTest::newRow("invalid-utf8-bad-continuation-1char") << raw("\x61\x80") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString;
|
||||||
QTest::newRow("invalid-utf8-2chars-2") << raw("\x62\xc3\xdf") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString;
|
QTest::newRow("invalid-utf8-bad-continuation-2chars-1") << raw("\x62\xc2\xc0") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString;
|
||||||
QTest::newRow("invalid-utf8-2chars-3") << raw("\x62\xc7\xf0") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString;
|
QTest::newRow("invalid-utf8-bad-continuation-2chars-2") << raw("\x62\xc3\xdf") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString;
|
||||||
QTest::newRow("invalid-utf8-3chars-1") << raw("\x63\xe0\xa0\xc0") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString;
|
QTest::newRow("invalid-utf8-bad-continuation-2chars-3") << raw("\x62\xc7\xf0") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString;
|
||||||
QTest::newRow("invalid-utf8-3chars-2") << raw("\x63\xe0\xc0\xa0") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString;
|
QTest::newRow("invalid-utf8-bad-continuation-3chars-1") << raw("\x63\xe0\xa0\xc0") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString;
|
||||||
QTest::newRow("invalid-utf8-4chars-1") << raw("\x64\xf0\x90\x80\xc0") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString;
|
QTest::newRow("invalid-utf8-bad-continuation-3chars-2") << raw("\x63\xe0\xc0\xa0") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString;
|
||||||
QTest::newRow("invalid-utf8-4chars-2") << raw("\x64\xf0\x90\xc0\x80") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString;
|
QTest::newRow("invalid-utf8-bad-continuation-4chars-1") << raw("\x64\xf0\x90\x80\xc0") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString;
|
||||||
QTest::newRow("invalid-utf8-4chars-3") << raw("\x64\xf0\xc0\x80\x80") << 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-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-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;
|
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-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-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-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;
|
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-fe") << raw("\x61\xfe") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString;
|
||||||
QTest::newRow("invalid-utf8-ff") << raw("\x61\xff") << 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-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-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;
|
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);
|
QFETCH(CborError, expectedError);
|
||||||
|
|
||||||
QString decoded;
|
QString decoded;
|
||||||
CborParser parser;
|
ParserWrapper w;
|
||||||
CborValue first;
|
CborError err = w.init(data);
|
||||||
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) + "\"");
|
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);
|
QCOMPARE(err, expectedError);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1549,12 +1733,11 @@ void tst_Parser::incompleteData()
|
|||||||
QFETCH(QString, expected);
|
QFETCH(QString, expected);
|
||||||
|
|
||||||
for (int len = 0; len < data.length() - 1; ++len) {
|
for (int len = 0; len < data.length() - 1; ++len) {
|
||||||
CborParser parser;
|
ParserWrapper w;
|
||||||
CborValue first;
|
CborError err = w.init(data.constData(), len);
|
||||||
CborError err = cbor_parser_init(reinterpret_cast<const quint8 *>(data.constData()), len, 0, &parser, &first);
|
|
||||||
if (!err) {
|
if (!err) {
|
||||||
QString decoded;
|
QString decoded;
|
||||||
err = parseOne(&first, &decoded);
|
err = parseOne(&w.first, &decoded);
|
||||||
}
|
}
|
||||||
if (err != CborErrorUnexpectedEOF)
|
if (err != CborErrorUnexpectedEOF)
|
||||||
qDebug() << "Length is" << len;
|
qDebug() << "Length is" << len;
|
||||||
@ -1583,14 +1766,13 @@ void tst_Parser::endPointer()
|
|||||||
QFETCH(int, offset);
|
QFETCH(int, offset);
|
||||||
|
|
||||||
QString decoded;
|
QString decoded;
|
||||||
CborParser parser;
|
ParserWrapper w;
|
||||||
CborValue first;
|
CborError err = w.init(data);
|
||||||
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) + "\"");
|
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) + "\"");
|
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()
|
void tst_Parser::recursionLimit_data()
|
||||||
@ -1638,24 +1820,23 @@ void tst_Parser::recursionLimit()
|
|||||||
{
|
{
|
||||||
QFETCH(QByteArray, data);
|
QFETCH(QByteArray, data);
|
||||||
|
|
||||||
CborParser parser;
|
ParserWrapper w;
|
||||||
CborValue first;
|
CborError err = w.init(data);
|
||||||
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) + "\"");
|
QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\"");
|
||||||
|
|
||||||
// check that it is valid:
|
// check that it is valid:
|
||||||
CborValue it = first;
|
CborValue it = w.first;
|
||||||
{
|
{
|
||||||
QString dummy;
|
QString dummy;
|
||||||
err = parseOne(&it, &dummy);
|
err = parseOne(&it, &dummy);
|
||||||
QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\"");
|
QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\"");
|
||||||
}
|
}
|
||||||
|
|
||||||
it = first;
|
it = w.first;
|
||||||
err = cbor_value_advance(&it);
|
err = cbor_value_advance(&it);
|
||||||
QCOMPARE(err, CborErrorNestingTooDeep);
|
QCOMPARE(err, CborErrorNestingTooDeep);
|
||||||
|
|
||||||
it = first;
|
it = w.first;
|
||||||
if (cbor_value_is_map(&it)) {
|
if (cbor_value_is_map(&it)) {
|
||||||
CborValue dummy;
|
CborValue dummy;
|
||||||
err = cbor_value_map_find_value(&it, "foo", &dummy);
|
err = cbor_value_map_find_value(&it, "foo", &dummy);
|
||||||
|
@ -77,15 +77,6 @@ static inline qint64 ticksToNanoseconds(qint64 ticks)
|
|||||||
return ticks * 1000000;
|
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()
|
static quint64 getTickCount()
|
||||||
{
|
{
|
||||||
|
@ -235,6 +235,12 @@ QObject *QMetaObject::newInstance(QGenericArgument val0,
|
|||||||
QGenericArgument val8,
|
QGenericArgument val8,
|
||||||
QGenericArgument val9) const
|
QGenericArgument val9) const
|
||||||
{
|
{
|
||||||
|
if (!inherits(&QObject::staticMetaObject))
|
||||||
|
{
|
||||||
|
qWarning("QMetaObject::newInstance: type %s does not inherit QObject", className());
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
QByteArray constructorName = className();
|
QByteArray constructorName = className();
|
||||||
{
|
{
|
||||||
int idx = constructorName.lastIndexOf(':');
|
int idx = constructorName.lastIndexOf(':');
|
||||||
|
@ -817,7 +817,7 @@ bool QTranslatorPrivate::do_load(const uchar *data, qsizetype len, const QString
|
|||||||
data += MagicLength;
|
data += MagicLength;
|
||||||
|
|
||||||
QStringList dependencies;
|
QStringList dependencies;
|
||||||
while (data < end - 4) {
|
while (data < end - 5) {
|
||||||
quint8 tag = read8(data++);
|
quint8 tag = read8(data++);
|
||||||
quint32 blockLen = read32(data);
|
quint32 blockLen = read32(data);
|
||||||
data += 4;
|
data += 4;
|
||||||
|
@ -101,6 +101,16 @@ static CborError _cbor_value_dup_string(const CborValue *, void **, size_t *, Cb
|
|||||||
Q_UNREACHABLE();
|
Q_UNREACHABLE();
|
||||||
return CborErrorInternalError;
|
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
|
QT_WARNING_POP
|
||||||
|
|
||||||
Q_DECLARE_TYPEINFO(CborEncoder, Q_PRIMITIVE_TYPE);
|
Q_DECLARE_TYPEINFO(CborEncoder, Q_PRIMITIVE_TYPE);
|
||||||
|
@ -260,21 +260,22 @@ namespace
|
|||||||
|
|
||||||
QByteArray replaceParameters(const QByteArray &original, const QShaderNode &node, const QShaderFormat &format)
|
QByteArray replaceParameters(const QByteArray &original, const QShaderNode &node, const QShaderFormat &format)
|
||||||
{
|
{
|
||||||
auto result = original;
|
QByteArray result = original;
|
||||||
|
|
||||||
for (const auto ¶meterName : node.parameterNames()) {
|
const QStringList parameterNames = node.parameterNames();
|
||||||
const auto placeholder = QByteArray(QByteArrayLiteral("$") + parameterName.toUtf8());
|
for (const QString ¶meterName : parameterNames) {
|
||||||
const auto parameter = node.parameter(parameterName);
|
const QByteArray placeholder = QByteArray(QByteArrayLiteral("$") + parameterName.toUtf8());
|
||||||
|
const QVariant parameter = node.parameter(parameterName);
|
||||||
if (parameter.userType() == qMetaTypeId<QShaderLanguage::StorageQualifier>()) {
|
if (parameter.userType() == qMetaTypeId<QShaderLanguage::StorageQualifier>()) {
|
||||||
const auto qualifier = parameter.value<QShaderLanguage::StorageQualifier>();
|
const QShaderLanguage::StorageQualifier qualifier = parameter.value<QShaderLanguage::StorageQualifier>();
|
||||||
const auto value = toGlsl(qualifier, format);
|
const QByteArray value = toGlsl(qualifier, format);
|
||||||
result.replace(placeholder, value);
|
result.replace(placeholder, value);
|
||||||
} else if (parameter.userType() == qMetaTypeId<QShaderLanguage::VariableType>()) {
|
} else if (parameter.userType() == qMetaTypeId<QShaderLanguage::VariableType>()) {
|
||||||
const auto type = parameter.value<QShaderLanguage::VariableType>();
|
const QShaderLanguage::VariableType type = parameter.value<QShaderLanguage::VariableType>();
|
||||||
const auto value = toGlsl(type);
|
const QByteArray value = toGlsl(type);
|
||||||
result.replace(placeholder, value);
|
result.replace(placeholder, value);
|
||||||
} else {
|
} else {
|
||||||
const auto value = parameter.toString().toUtf8();
|
const QByteArray value = parameter.toString().toUtf8();
|
||||||
result.replace(placeholder, value);
|
result.replace(placeholder, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -288,17 +289,17 @@ QByteArray QShaderGenerator::createShaderCode(const QStringList &enabledLayers)
|
|||||||
auto code = QByteArrayList();
|
auto code = QByteArrayList();
|
||||||
|
|
||||||
if (format.isValid()) {
|
if (format.isValid()) {
|
||||||
const auto isGLES = format.api() == QShaderFormat::OpenGLES;
|
const bool isGLES = format.api() == QShaderFormat::OpenGLES;
|
||||||
const auto major = format.version().majorVersion();
|
const int major = format.version().majorVersion();
|
||||||
const auto minor = format.version().minorVersion();
|
const int minor = format.version().minorVersion();
|
||||||
|
|
||||||
const auto version = major == 2 && isGLES ? 100
|
const int version = major == 2 && isGLES ? 100
|
||||||
: major == 3 && isGLES ? 300
|
: major == 3 && isGLES ? 300
|
||||||
: major == 2 ? 100 + 10 * (minor + 1)
|
: major == 2 ? 100 + 10 * (minor + 1)
|
||||||
: major == 3 && minor <= 2 ? 100 + 10 * (minor + 3)
|
: major == 3 && minor <= 2 ? 100 + 10 * (minor + 3)
|
||||||
: major * 100 + minor * 10;
|
: major * 100 + minor * 10;
|
||||||
|
|
||||||
const auto profile = isGLES && version > 100 ? QByteArrayLiteral(" es")
|
const QByteArray profile = isGLES && version > 100 ? QByteArrayLiteral(" es")
|
||||||
: version >= 150 && format.api() == QShaderFormat::OpenGLCoreProfile ? QByteArrayLiteral(" core")
|
: version >= 150 && format.api() == QShaderFormat::OpenGLCoreProfile ? QByteArrayLiteral(" core")
|
||||||
: version >= 150 && format.api() == QShaderFormat::OpenGLCompatibilityProfile ? QByteArrayLiteral(" compatibility")
|
: version >= 150 && format.api() == QShaderFormat::OpenGLCompatibilityProfile ? QByteArrayLiteral(" compatibility")
|
||||||
: QByteArray();
|
: QByteArray();
|
||||||
@ -313,9 +314,11 @@ QByteArray QShaderGenerator::createShaderCode(const QStringList &enabledLayers)
|
|||||||
[enabledLayers] (const QString &s) { return enabledLayers.contains(s); });
|
[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())) {
|
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);
|
code << replaceParameters(snippet, node, format);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -325,16 +328,17 @@ QByteArray QShaderGenerator::createShaderCode(const QStringList &enabledLayers)
|
|||||||
code << QByteArrayLiteral("void main()");
|
code << QByteArrayLiteral("void main()");
|
||||||
code << QByteArrayLiteral("{");
|
code << QByteArrayLiteral("{");
|
||||||
|
|
||||||
for (const auto &statement : graph.createStatements(enabledLayers)) {
|
for (const QShaderGraph::Statement &statement : graph.createStatements(enabledLayers)) {
|
||||||
const auto node = statement.node;
|
const QShaderNode node = statement.node;
|
||||||
auto line = node.rule(format).substitution;
|
QByteArray line = node.rule(format).substitution;
|
||||||
for (const auto &port : node.ports()) {
|
const QVector<QShaderNodePort> ports = node.ports();
|
||||||
const auto portName = port.name;
|
for (const QShaderNodePort &port : ports) {
|
||||||
const auto portDirection = port.direction;
|
const QString portName = port.name;
|
||||||
const auto isInput = port.direction == QShaderNodePort::Input;
|
const QShaderNodePort::Direction portDirection = port.direction;
|
||||||
|
const bool isInput = port.direction == QShaderNodePort::Input;
|
||||||
|
|
||||||
const auto portIndex = statement.portIndex(portDirection, portName);
|
const int portIndex = statement.portIndex(portDirection, portName);
|
||||||
const auto variableIndex = isInput ? statement.inputs.at(portIndex)
|
const int variableIndex = isInput ? statement.inputs.at(portIndex)
|
||||||
: statement.outputs.at(portIndex);
|
: statement.outputs.at(portIndex);
|
||||||
if (variableIndex < 0)
|
if (variableIndex < 0)
|
||||||
continue;
|
continue;
|
||||||
|
@ -82,8 +82,8 @@ namespace
|
|||||||
auto statement = QShaderGraph::Statement();
|
auto statement = QShaderGraph::Statement();
|
||||||
statement.node = node;
|
statement.node = node;
|
||||||
|
|
||||||
const auto ports = node.ports();
|
const QVector<QShaderNodePort> ports = node.ports();
|
||||||
for (const auto &port : ports) {
|
for (const QShaderNodePort &port : ports) {
|
||||||
if (port.direction == QShaderNodePort::Input) {
|
if (port.direction == QShaderNodePort::Input) {
|
||||||
statement.inputs.append(-1);
|
statement.inputs.append(-1);
|
||||||
} else {
|
} else {
|
||||||
@ -99,19 +99,19 @@ namespace
|
|||||||
const QUuid &uuid)
|
const QUuid &uuid)
|
||||||
{
|
{
|
||||||
auto targetStatement = idHash.value(uuid);
|
auto targetStatement = idHash.value(uuid);
|
||||||
for (const auto &edge : edges) {
|
for (const QShaderGraph::Edge &edge : edges) {
|
||||||
if (edge.targetNodeUuid != uuid)
|
if (edge.targetNodeUuid != uuid)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
const auto sourceStatement = idHash.value(edge.sourceNodeUuid);
|
const QShaderGraph::Statement sourceStatement = idHash.value(edge.sourceNodeUuid);
|
||||||
const auto sourcePortIndex = sourceStatement.portIndex(QShaderNodePort::Output, edge.sourcePortName);
|
const int sourcePortIndex = sourceStatement.portIndex(QShaderNodePort::Output, edge.sourcePortName);
|
||||||
const auto targetPortIndex = targetStatement.portIndex(QShaderNodePort::Input, edge.targetPortName);
|
const int targetPortIndex = targetStatement.portIndex(QShaderNodePort::Input, edge.targetPortName);
|
||||||
|
|
||||||
if (sourcePortIndex < 0 || targetPortIndex < 0)
|
if (sourcePortIndex < 0 || targetPortIndex < 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
const auto &sourceOutputs = sourceStatement.outputs;
|
const QVector<int> sourceOutputs = sourceStatement.outputs;
|
||||||
auto &targetInputs = targetStatement.inputs;
|
QVector<int> &targetInputs = targetStatement.inputs;
|
||||||
targetInputs[targetPortIndex] = sourceOutputs[sourcePortIndex];
|
targetInputs[targetPortIndex] = sourceOutputs[sourcePortIndex];
|
||||||
}
|
}
|
||||||
return targetStatement;
|
return targetStatement;
|
||||||
@ -125,9 +125,9 @@ QUuid QShaderGraph::Statement::uuid() const noexcept
|
|||||||
|
|
||||||
int QShaderGraph::Statement::portIndex(QShaderNodePort::Direction direction, const QString &portName) 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;
|
int index = 0;
|
||||||
for (const auto &port : ports) {
|
for (const QShaderNodePort &port : ports) {
|
||||||
if (port.name == portName && port.direction == direction)
|
if (port.name == portName && port.direction == direction)
|
||||||
return index;
|
return index;
|
||||||
else if (port.direction == direction)
|
else if (port.direction == direction)
|
||||||
@ -180,7 +180,7 @@ QVector<QShaderGraph::Statement> QShaderGraph::createStatements(const QStringLis
|
|||||||
[enabledLayers] (const QString &s) { return enabledLayers.contains(s); });
|
[enabledLayers] (const QString &s) { return enabledLayers.contains(s); });
|
||||||
};
|
};
|
||||||
|
|
||||||
const auto enabledNodes = [this, intersectsEnabledLayers] {
|
const QVector<QShaderNode> enabledNodes = [this, intersectsEnabledLayers] {
|
||||||
auto res = QVector<QShaderNode>();
|
auto res = QVector<QShaderNode>();
|
||||||
std::copy_if(m_nodes.cbegin(), m_nodes.cend(),
|
std::copy_if(m_nodes.cbegin(), m_nodes.cend(),
|
||||||
std::back_inserter(res),
|
std::back_inserter(res),
|
||||||
@ -190,7 +190,7 @@ QVector<QShaderGraph::Statement> QShaderGraph::createStatements(const QStringLis
|
|||||||
return res;
|
return res;
|
||||||
}();
|
}();
|
||||||
|
|
||||||
const auto enabledEdges = [this, intersectsEnabledLayers] {
|
const QVector<Edge> enabledEdges = [this, intersectsEnabledLayers] {
|
||||||
auto res = QVector<Edge>();
|
auto res = QVector<Edge>();
|
||||||
std::copy_if(m_edges.cbegin(), m_edges.cend(),
|
std::copy_if(m_edges.cbegin(), m_edges.cend(),
|
||||||
std::back_inserter(res),
|
std::back_inserter(res),
|
||||||
@ -200,18 +200,18 @@ QVector<QShaderGraph::Statement> QShaderGraph::createStatements(const QStringLis
|
|||||||
return res;
|
return res;
|
||||||
}();
|
}();
|
||||||
|
|
||||||
const auto idHash = [enabledNodes] {
|
const QHash<QUuid, Statement> idHash = [enabledNodes] {
|
||||||
auto nextVarId = 0;
|
auto nextVarId = 0;
|
||||||
auto res = QHash<QUuid, Statement>();
|
auto res = QHash<QUuid, Statement>();
|
||||||
for (const auto &node : enabledNodes)
|
for (const QShaderNode &node : enabledNodes)
|
||||||
res.insert(node.uuid(), nodeToStatement(node, nextVarId));
|
res.insert(node.uuid(), nodeToStatement(node, nextVarId));
|
||||||
return res;
|
return res;
|
||||||
}();
|
}();
|
||||||
|
|
||||||
auto result = QVector<Statement>();
|
auto result = QVector<Statement>();
|
||||||
auto currentEdges = enabledEdges;
|
QVector<Edge> currentEdges = enabledEdges;
|
||||||
auto currentUuids = [enabledNodes] {
|
QVector<QUuid> currentUuids = [enabledNodes] {
|
||||||
const auto inputs = copyOutputNodes(enabledNodes);
|
const QVector<QShaderNode> inputs = copyOutputNodes(enabledNodes);
|
||||||
auto res = QVector<QUuid>();
|
auto res = QVector<QUuid>();
|
||||||
std::transform(inputs.cbegin(), inputs.cend(),
|
std::transform(inputs.cbegin(), inputs.cend(),
|
||||||
std::back_inserter(res),
|
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
|
// because we want to track the dependencies from the output nodes and not the
|
||||||
// input nodes
|
// input nodes
|
||||||
while (!currentUuids.isEmpty()) {
|
while (!currentUuids.isEmpty()) {
|
||||||
const auto uuid = currentUuids.takeFirst();
|
const QUuid uuid = currentUuids.takeFirst();
|
||||||
result.append(completeStatement(idHash, enabledEdges, uuid));
|
result.append(completeStatement(idHash, enabledEdges, uuid));
|
||||||
|
|
||||||
const auto outgoing = outgoingEdges(currentEdges, uuid);
|
const QVector<QShaderGraph::Edge> outgoing = outgoingEdges(currentEdges, uuid);
|
||||||
for (const auto &outgoingEdge : outgoing) {
|
for (const QShaderGraph::Edge &outgoingEdge : outgoing) {
|
||||||
currentEdges.removeAll(outgoingEdge);
|
currentEdges.removeAll(outgoingEdge);
|
||||||
const QUuid nextUuid = outgoingEdge.sourceNodeUuid;
|
const QUuid nextUuid = outgoingEdge.sourceNodeUuid;
|
||||||
const auto incoming = incomingEdges(currentEdges, nextUuid);
|
const QVector<QShaderGraph::Edge> incoming = incomingEdges(currentEdges, nextUuid);
|
||||||
if (incoming.isEmpty()) {
|
if (incoming.isEmpty()) {
|
||||||
currentUuids.append(nextUuid);
|
currentUuids.append(nextUuid);
|
||||||
}
|
}
|
||||||
|
@ -99,7 +99,7 @@ void QShaderGraphLoader::load()
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
auto error = QJsonParseError();
|
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) {
|
if (error.error != QJsonParseError::NoError) {
|
||||||
qWarning() << "Invalid JSON document:" << error.errorString();
|
qWarning() << "Invalid JSON document:" << error.errorString();
|
||||||
@ -113,16 +113,16 @@ void QShaderGraphLoader::load()
|
|||||||
return;
|
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()) {
|
if (!nodesValue.isArray()) {
|
||||||
qWarning() << "Invalid nodes property, should be an array";
|
qWarning() << "Invalid nodes property, should be an array";
|
||||||
m_status = Error;
|
m_status = Error;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto edgesValue = root.value(QStringLiteral("edges"));
|
const QJsonValue edgesValue = root.value(QStringLiteral("edges"));
|
||||||
if (!edgesValue.isArray()) {
|
if (!edgesValue.isArray()) {
|
||||||
qWarning() << "Invalid edges property, should be an array";
|
qWarning() << "Invalid edges property, should be an array";
|
||||||
m_status = Error;
|
m_status = Error;
|
||||||
@ -131,7 +131,7 @@ void QShaderGraphLoader::load()
|
|||||||
|
|
||||||
bool hasError = false;
|
bool hasError = false;
|
||||||
|
|
||||||
const auto prototypesValue = root.value(QStringLiteral("prototypes"));
|
const QJsonValue prototypesValue = root.value(QStringLiteral("prototypes"));
|
||||||
if (!prototypesValue.isUndefined()) {
|
if (!prototypesValue.isUndefined()) {
|
||||||
if (prototypesValue.isObject()) {
|
if (prototypesValue.isObject()) {
|
||||||
QShaderNodesLoader loader;
|
QShaderNodesLoader loader;
|
||||||
@ -144,60 +144,60 @@ void QShaderGraphLoader::load()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto nodes = nodesValue.toArray();
|
const QJsonArray nodes = nodesValue.toArray();
|
||||||
for (const auto &nodeValue : nodes) {
|
for (const QJsonValue &nodeValue : nodes) {
|
||||||
if (!nodeValue.isObject()) {
|
if (!nodeValue.isObject()) {
|
||||||
qWarning() << "Invalid node found";
|
qWarning() << "Invalid node found";
|
||||||
hasError = true;
|
hasError = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto nodeObject = nodeValue.toObject();
|
const QJsonObject nodeObject = nodeValue.toObject();
|
||||||
|
|
||||||
const auto uuidString = nodeObject.value(QStringLiteral("uuid")).toString();
|
const QString uuidString = nodeObject.value(QStringLiteral("uuid")).toString();
|
||||||
const auto uuid = QUuid(uuidString);
|
const QUuid uuid = QUuid(uuidString);
|
||||||
if (uuid.isNull()) {
|
if (uuid.isNull()) {
|
||||||
qWarning() << "Invalid UUID found in node:" << uuidString;
|
qWarning() << "Invalid UUID found in node:" << uuidString;
|
||||||
hasError = true;
|
hasError = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto type = nodeObject.value(QStringLiteral("type")).toString();
|
const QString type = nodeObject.value(QStringLiteral("type")).toString();
|
||||||
if (!m_prototypes.contains(type)) {
|
if (!m_prototypes.contains(type)) {
|
||||||
qWarning() << "Unsupported node type found:" << type;
|
qWarning() << "Unsupported node type found:" << type;
|
||||||
hasError = true;
|
hasError = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto layersArray = nodeObject.value(QStringLiteral("layers")).toArray();
|
const QJsonArray layersArray = nodeObject.value(QStringLiteral("layers")).toArray();
|
||||||
auto layers = QStringList();
|
auto layers = QStringList();
|
||||||
for (const auto &layerValue : layersArray) {
|
for (const QJsonValue &layerValue : layersArray) {
|
||||||
layers.append(layerValue.toString());
|
layers.append(layerValue.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
auto node = m_prototypes.value(type);
|
QShaderNode node = m_prototypes.value(type);
|
||||||
node.setUuid(uuid);
|
node.setUuid(uuid);
|
||||||
node.setLayers(layers);
|
node.setLayers(layers);
|
||||||
|
|
||||||
const auto parametersValue = nodeObject.value(QStringLiteral("parameters"));
|
const QJsonValue parametersValue = nodeObject.value(QStringLiteral("parameters"));
|
||||||
if (parametersValue.isObject()) {
|
if (parametersValue.isObject()) {
|
||||||
const auto parametersObject = parametersValue.toObject();
|
const QJsonObject parametersObject = parametersValue.toObject();
|
||||||
for (const auto ¶meterName : parametersObject.keys()) {
|
for (const QString ¶meterName : parametersObject.keys()) {
|
||||||
const auto parameterValue = parametersObject.value(parameterName);
|
const QJsonValue parameterValue = parametersObject.value(parameterName);
|
||||||
if (parameterValue.isObject()) {
|
if (parameterValue.isObject()) {
|
||||||
const auto parameterObject = parameterValue.toObject();
|
const QJsonObject parameterObject = parameterValue.toObject();
|
||||||
const auto type = parameterObject.value(QStringLiteral("type")).toString();
|
const QString type = parameterObject.value(QStringLiteral("type")).toString();
|
||||||
const auto typeId = QMetaType::type(type.toUtf8());
|
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);
|
auto variant = QVariant(value);
|
||||||
|
|
||||||
if (QMetaType::typeFlags(typeId) & QMetaType::IsEnumeration) {
|
if (QMetaType::typeFlags(typeId) & QMetaType::IsEnumeration) {
|
||||||
const auto metaObject = QMetaType::metaObjectForType(typeId);
|
const QMetaObject *metaObject = QMetaType::metaObjectForType(typeId);
|
||||||
const auto className = metaObject->className();
|
const char *className = metaObject->className();
|
||||||
const auto enumName = type.mid(static_cast<int>(qstrlen(className)) + 2).toUtf8();
|
const QByteArray enumName = type.mid(static_cast<int>(qstrlen(className)) + 2).toUtf8();
|
||||||
const auto metaEnum = metaObject->enumerator(metaObject->indexOfEnumerator(enumName));
|
const QMetaEnum metaEnum = metaObject->enumerator(metaObject->indexOfEnumerator(enumName));
|
||||||
const auto enumValue = metaEnum.keyToValue(value.toUtf8());
|
const int enumValue = metaEnum.keyToValue(value.toUtf8());
|
||||||
variant = QVariant(enumValue);
|
variant = QVariant(enumValue);
|
||||||
variant.convert(typeId);
|
variant.convert(typeId);
|
||||||
} else {
|
} else {
|
||||||
@ -213,39 +213,39 @@ void QShaderGraphLoader::load()
|
|||||||
m_graph.addNode(node);
|
m_graph.addNode(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto edges = edgesValue.toArray();
|
const QJsonArray edges = edgesValue.toArray();
|
||||||
for (const auto &edgeValue : edges) {
|
for (const QJsonValue &edgeValue : edges) {
|
||||||
if (!edgeValue.isObject()) {
|
if (!edgeValue.isObject()) {
|
||||||
qWarning() << "Invalid edge found";
|
qWarning() << "Invalid edge found";
|
||||||
hasError = true;
|
hasError = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto edgeObject = edgeValue.toObject();
|
const QJsonObject edgeObject = edgeValue.toObject();
|
||||||
|
|
||||||
const auto sourceUuidString = edgeObject.value(QStringLiteral("sourceUuid")).toString();
|
const QString sourceUuidString = edgeObject.value(QStringLiteral("sourceUuid")).toString();
|
||||||
const auto sourceUuid = QUuid(sourceUuidString);
|
const QUuid sourceUuid = QUuid(sourceUuidString);
|
||||||
if (sourceUuid.isNull()) {
|
if (sourceUuid.isNull()) {
|
||||||
qWarning() << "Invalid source UUID found in edge:" << sourceUuidString;
|
qWarning() << "Invalid source UUID found in edge:" << sourceUuidString;
|
||||||
hasError = true;
|
hasError = true;
|
||||||
continue;
|
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 QString targetUuidString = edgeObject.value(QStringLiteral("targetUuid")).toString();
|
||||||
const auto targetUuid = QUuid(targetUuidString);
|
const QUuid targetUuid = QUuid(targetUuidString);
|
||||||
if (targetUuid.isNull()) {
|
if (targetUuid.isNull()) {
|
||||||
qWarning() << "Invalid target UUID found in edge:" << targetUuidString;
|
qWarning() << "Invalid target UUID found in edge:" << targetUuidString;
|
||||||
hasError = true;
|
hasError = true;
|
||||||
continue;
|
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();
|
auto layers = QStringList();
|
||||||
for (const auto &layerValue : layersArray) {
|
for (const QJsonValue &layerValue : layersArray) {
|
||||||
layers.append(layerValue.toString());
|
layers.append(layerValue.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,7 +84,7 @@ void QShaderNodesLoader::load()
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
auto error = QJsonParseError();
|
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) {
|
if (error.error != QJsonParseError::NoError) {
|
||||||
qWarning() << "Invalid JSON document:" << error.errorString();
|
qWarning() << "Invalid JSON document:" << error.errorString();
|
||||||
@ -98,7 +98,7 @@ void QShaderNodesLoader::load()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto root = document.object();
|
const QJsonObject root = document.object();
|
||||||
load(root);
|
load(root);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,22 +106,22 @@ void QShaderNodesLoader::load(const QJsonObject &prototypesObject)
|
|||||||
{
|
{
|
||||||
bool hasError = false;
|
bool hasError = false;
|
||||||
|
|
||||||
for (const auto &property : prototypesObject.keys()) {
|
for (const QString &property : prototypesObject.keys()) {
|
||||||
const auto nodeValue = prototypesObject.value(property);
|
const QJsonValue nodeValue = prototypesObject.value(property);
|
||||||
if (!nodeValue.isObject()) {
|
if (!nodeValue.isObject()) {
|
||||||
qWarning() << "Invalid node found";
|
qWarning() << "Invalid node found";
|
||||||
hasError = true;
|
hasError = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto nodeObject = nodeValue.toObject();
|
const QJsonObject nodeObject = nodeValue.toObject();
|
||||||
|
|
||||||
auto node = QShaderNode();
|
auto node = QShaderNode();
|
||||||
|
|
||||||
const auto inputsValue = nodeObject.value(QStringLiteral("inputs"));
|
const QJsonValue inputsValue = nodeObject.value(QStringLiteral("inputs"));
|
||||||
if (inputsValue.isArray()) {
|
if (inputsValue.isArray()) {
|
||||||
const auto inputsArray = inputsValue.toArray();
|
const QJsonArray inputsArray = inputsValue.toArray();
|
||||||
for (const auto &inputValue : inputsArray) {
|
for (const QJsonValue &inputValue : inputsArray) {
|
||||||
if (!inputValue.isString()) {
|
if (!inputValue.isString()) {
|
||||||
qWarning() << "Non-string value in inputs";
|
qWarning() << "Non-string value in inputs";
|
||||||
hasError = true;
|
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()) {
|
if (outputsValue.isArray()) {
|
||||||
const auto outputsArray = outputsValue.toArray();
|
const QJsonArray outputsArray = outputsValue.toArray();
|
||||||
for (const auto &outputValue : outputsArray) {
|
for (const QJsonValue &outputValue : outputsArray) {
|
||||||
if (!outputValue.isString()) {
|
if (!outputValue.isString()) {
|
||||||
qWarning() << "Non-string value in outputs";
|
qWarning() << "Non-string value in outputs";
|
||||||
hasError = true;
|
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()) {
|
if (parametersValue.isObject()) {
|
||||||
const auto parametersObject = parametersValue.toObject();
|
const QJsonObject parametersObject = parametersValue.toObject();
|
||||||
for (const auto ¶meterName : parametersObject.keys()) {
|
for (const QString ¶meterName : parametersObject.keys()) {
|
||||||
const auto parameterValue = parametersObject.value(parameterName);
|
const QJsonValue parameterValue = parametersObject.value(parameterName);
|
||||||
if (parameterValue.isObject()) {
|
if (parameterValue.isObject()) {
|
||||||
const auto parameterObject = parameterValue.toObject();
|
const QJsonObject parameterObject = parameterValue.toObject();
|
||||||
const auto type = parameterObject.value(QStringLiteral("type")).toString();
|
const QString type = parameterObject.value(QStringLiteral("type")).toString();
|
||||||
const auto typeId = QMetaType::type(type.toUtf8());
|
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);
|
auto variant = QVariant(value);
|
||||||
|
|
||||||
if (QMetaType::typeFlags(typeId) & QMetaType::IsEnumeration) {
|
if (QMetaType::typeFlags(typeId) & QMetaType::IsEnumeration) {
|
||||||
const auto metaObject = QMetaType::metaObjectForType(typeId);
|
const QMetaObject *metaObject = QMetaType::metaObjectForType(typeId);
|
||||||
const auto className = metaObject->className();
|
const char *className = metaObject->className();
|
||||||
const auto enumName = type.mid(static_cast<int>(qstrlen(className)) + 2).toUtf8();
|
const QByteArray enumName = type.mid(static_cast<int>(qstrlen(className)) + 2).toUtf8();
|
||||||
const auto metaEnum = metaObject->enumerator(metaObject->indexOfEnumerator(enumName));
|
const QMetaEnum metaEnum = metaObject->enumerator(metaObject->indexOfEnumerator(enumName));
|
||||||
const auto enumValue = metaEnum.keyToValue(value.toUtf8());
|
const int enumValue = metaEnum.keyToValue(value.toUtf8());
|
||||||
variant = QVariant(enumValue);
|
variant = QVariant(enumValue);
|
||||||
variant.convert(typeId);
|
variant.convert(typeId);
|
||||||
} else {
|
} 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()) {
|
if (rulesValue.isArray()) {
|
||||||
const auto rulesArray = rulesValue.toArray();
|
const QJsonArray rulesArray = rulesValue.toArray();
|
||||||
for (const auto &ruleValue : rulesArray) {
|
for (const QJsonValue &ruleValue : rulesArray) {
|
||||||
if (!ruleValue.isObject()) {
|
if (!ruleValue.isObject()) {
|
||||||
qWarning() << "Rules should be objects";
|
qWarning() << "Rules should be objects";
|
||||||
hasError = true;
|
hasError = true;
|
||||||
break;
|
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()) {
|
if (!formatValue.isObject()) {
|
||||||
qWarning() << "Format is mandatory in rules and should be an object";
|
qWarning() << "Format is mandatory in rules and should be an object";
|
||||||
hasError = true;
|
hasError = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto formatObject = formatValue.toObject();
|
const QJsonObject formatObject = formatValue.toObject();
|
||||||
auto format = QShaderFormat();
|
auto format = QShaderFormat();
|
||||||
|
|
||||||
const auto apiValue = formatObject.value(QStringLiteral("api"));
|
const QJsonValue apiValue = formatObject.value(QStringLiteral("api"));
|
||||||
if (!apiValue.isString()) {
|
if (!apiValue.isString()) {
|
||||||
qWarning() << "Format API must be a string";
|
qWarning() << "Format API must be a string";
|
||||||
hasError = true;
|
hasError = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto api = apiValue.toString();
|
const QString api = apiValue.toString();
|
||||||
format.setApi(api == QStringLiteral("OpenGLES") ? QShaderFormat::OpenGLES
|
format.setApi(api == QStringLiteral("OpenGLES") ? QShaderFormat::OpenGLES
|
||||||
: api == QStringLiteral("OpenGLNoProfile") ? QShaderFormat::OpenGLNoProfile
|
: api == QStringLiteral("OpenGLNoProfile") ? QShaderFormat::OpenGLNoProfile
|
||||||
: api == QStringLiteral("OpenGLCoreProfile") ? QShaderFormat::OpenGLCoreProfile
|
: api == QStringLiteral("OpenGLCoreProfile") ? QShaderFormat::OpenGLCoreProfile
|
||||||
@ -224,8 +224,8 @@ void QShaderNodesLoader::load(const QJsonObject &prototypesObject)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto majorValue = formatObject.value(QStringLiteral("major"));
|
const QJsonValue majorValue = formatObject.value(QStringLiteral("major"));
|
||||||
const auto minorValue = formatObject.value(QStringLiteral("minor"));
|
const QJsonValue minorValue = formatObject.value(QStringLiteral("minor"));
|
||||||
if (!majorValue.isDouble() || !minorValue.isDouble()) {
|
if (!majorValue.isDouble() || !minorValue.isDouble()) {
|
||||||
qWarning() << "Format major and minor version must be values";
|
qWarning() << "Format major and minor version must be values";
|
||||||
hasError = true;
|
hasError = true;
|
||||||
@ -233,28 +233,28 @@ void QShaderNodesLoader::load(const QJsonObject &prototypesObject)
|
|||||||
}
|
}
|
||||||
format.setVersion(QVersionNumber(majorValue.toInt(), minorValue.toInt()));
|
format.setVersion(QVersionNumber(majorValue.toInt(), minorValue.toInt()));
|
||||||
|
|
||||||
const auto extensionsValue = formatObject.value(QStringLiteral("extensions"));
|
const QJsonValue extensionsValue = formatObject.value(QStringLiteral("extensions"));
|
||||||
const auto extensionsArray = extensionsValue.toArray();
|
const QJsonArray extensionsArray = extensionsValue.toArray();
|
||||||
auto extensions = QStringList();
|
auto extensions = QStringList();
|
||||||
std::transform(extensionsArray.constBegin(), extensionsArray.constEnd(),
|
std::transform(extensionsArray.constBegin(), extensionsArray.constEnd(),
|
||||||
std::back_inserter(extensions),
|
std::back_inserter(extensions),
|
||||||
[] (const QJsonValue &extensionValue) { return extensionValue.toString(); });
|
[] (const QJsonValue &extensionValue) { return extensionValue.toString(); });
|
||||||
format.setExtensions(extensions);
|
format.setExtensions(extensions);
|
||||||
|
|
||||||
const auto vendor = formatObject.value(QStringLiteral("vendor")).toString();
|
const QString vendor = formatObject.value(QStringLiteral("vendor")).toString();
|
||||||
format.setVendor(vendor);
|
format.setVendor(vendor);
|
||||||
|
|
||||||
const auto substitutionValue = ruleObject.value(QStringLiteral("substitution"));
|
const QJsonValue substitutionValue = ruleObject.value(QStringLiteral("substitution"));
|
||||||
if (!substitutionValue.isString()) {
|
if (!substitutionValue.isString()) {
|
||||||
qWarning() << "Substitution needs to be a string";
|
qWarning() << "Substitution needs to be a string";
|
||||||
hasError = true;
|
hasError = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto substitution = substitutionValue.toString().toUtf8();
|
const QByteArray substitution = substitutionValue.toString().toUtf8();
|
||||||
|
|
||||||
const auto snippetsValue = ruleObject.value(QStringLiteral("headerSnippets"));
|
const QJsonValue snippetsValue = ruleObject.value(QStringLiteral("headerSnippets"));
|
||||||
const auto snippetsArray = snippetsValue.toArray();
|
const QJsonArray snippetsArray = snippetsValue.toArray();
|
||||||
auto snippets = QByteArrayList();
|
auto snippets = QByteArrayList();
|
||||||
std::transform(snippetsArray.constBegin(), snippetsArray.constEnd(),
|
std::transform(snippetsArray.constBegin(), snippetsArray.constEnd(),
|
||||||
std::back_inserter(snippets),
|
std::back_inserter(snippets),
|
||||||
|
@ -66,6 +66,11 @@ void QEglFSVivWaylandIntegration::platformInit()
|
|||||||
mScreenSize.setWidth(width);
|
mScreenSize.setWidth(width);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QEglFSVivWaylandIntegration::platformDestroy()
|
||||||
|
{
|
||||||
|
wl_display_destroy(mWaylandDisplay);
|
||||||
|
}
|
||||||
|
|
||||||
QSize QEglFSVivWaylandIntegration::screenSize() const
|
QSize QEglFSVivWaylandIntegration::screenSize() const
|
||||||
{
|
{
|
||||||
return mScreenSize;
|
return mScreenSize;
|
||||||
|
@ -49,6 +49,7 @@ class QEglFSVivWaylandIntegration : public QEglFSDeviceIntegration
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void platformInit() override;
|
void platformInit() override;
|
||||||
|
void platformDestroy() override;
|
||||||
QSize screenSize() const override;
|
QSize screenSize() const override;
|
||||||
EGLNativeWindowType createNativeWindow(QPlatformWindow *window, const QSize &size, const QSurfaceFormat &format) override;
|
EGLNativeWindowType createNativeWindow(QPlatformWindow *window, const QSize &size, const QSurfaceFormat &format) override;
|
||||||
void destroyNativeWindow(EGLNativeWindowType window) override;
|
void destroyNativeWindow(EGLNativeWindowType window) override;
|
||||||
|
@ -1453,26 +1453,41 @@ static QString createTemporaryItemCopy(QWindowsShellItem &qItem, QString *errorM
|
|||||||
return result;
|
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> QWindowsNativeOpenFileDialog::dialogResult() const
|
||||||
{
|
{
|
||||||
QList<QUrl> result;
|
QList<QUrl> result;
|
||||||
IShellItemArray *items = nullptr;
|
IShellItemArray *items = nullptr;
|
||||||
if (SUCCEEDED(openFileDialog()->GetResults(&items)) && items) {
|
if (SUCCEEDED(openFileDialog()->GetResults(&items)) && items) {
|
||||||
|
QString errorMessage;
|
||||||
for (IShellItem *item : QWindowsShellItem::itemsFromItemArray(items)) {
|
for (IShellItem *item : QWindowsShellItem::itemsFromItemArray(items)) {
|
||||||
QWindowsShellItem qItem(item);
|
QWindowsShellItem qItem(item);
|
||||||
const QString path = qItem.path();
|
const QUrl url = itemToDialogUrl(qItem, &errorMessage);
|
||||||
if (path.isEmpty() && !qItem.isDir()) {
|
if (!url.isValid()) {
|
||||||
QString errorMessage;
|
qWarning("%s", qPrintable(errorMessage));
|
||||||
const QString temporaryCopy = createTemporaryItemCopy(qItem, &errorMessage);
|
result.clear();
|
||||||
if (temporaryCopy.isEmpty()) {
|
break;
|
||||||
qWarning().noquote() << "Unable to create a local copy of" << qItem
|
|
||||||
<< ": " << errorMessage;
|
|
||||||
} else {
|
|
||||||
result.append(QUrl::fromLocalFile(temporaryCopy));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
result.append(qItem.url());
|
|
||||||
}
|
}
|
||||||
|
result.append(url);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
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))
|
if (mode == property(PPK_Duplex).toInt() || !d->m_printDevice.supportedDuplexModes().contains(mode))
|
||||||
break;
|
break;
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case QPrinter::DuplexNone:
|
case QPrint::DuplexNone:
|
||||||
d->devMode->dmDuplex = DMDUP_SIMPLEX;
|
d->devMode->dmDuplex = DMDUP_SIMPLEX;
|
||||||
break;
|
break;
|
||||||
case QPrinter::DuplexAuto:
|
case QPrint::DuplexAuto:
|
||||||
d->devMode->dmDuplex = d->m_pageLayout.orientation() == QPageLayout::Landscape ? DMDUP_HORIZONTAL : DMDUP_VERTICAL;
|
d->devMode->dmDuplex = d->m_pageLayout.orientation() == QPageLayout::Landscape ? DMDUP_HORIZONTAL : DMDUP_VERTICAL;
|
||||||
break;
|
break;
|
||||||
case QPrinter::DuplexLongSide:
|
case QPrint::DuplexLongSide:
|
||||||
d->devMode->dmDuplex = DMDUP_VERTICAL;
|
d->devMode->dmDuplex = DMDUP_VERTICAL;
|
||||||
break;
|
break;
|
||||||
case QPrinter::DuplexShortSide:
|
case QPrint::DuplexShortSide:
|
||||||
d->devMode->dmDuplex = DMDUP_HORIZONTAL;
|
d->devMode->dmDuplex = DMDUP_HORIZONTAL;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -1581,29 +1581,6 @@ void QTableView::paintEvent(QPaintEvent *event)
|
|||||||
colp += columnWidth(col) - gridSize;
|
colp += columnWidth(col) - gridSize;
|
||||||
painter.drawLine(colp, dirtyArea.top(), colp, dirtyArea.bottom());
|
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);
|
painter.setPen(old);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1878,7 +1855,7 @@ QModelIndex QTableView::moveCursor(CursorAction cursorAction, Qt::KeyboardModifi
|
|||||||
visualColumn = d->nextActiveVisualColumn(visualRow, right, -1,
|
visualColumn = d->nextActiveVisualColumn(visualRow, right, -1,
|
||||||
QTableViewPrivate::SearchDirection::Decreasing);
|
QTableViewPrivate::SearchDirection::Decreasing);
|
||||||
if (modifiers & Qt::ControlModifier)
|
if (modifiers & Qt::ControlModifier)
|
||||||
visualRow = d->nextActiveVisualRow(bottom, current.column(), -1,
|
visualRow = d->nextActiveVisualRow(bottom, visualColumn, -1,
|
||||||
QTableViewPrivate::SearchDirection::Decreasing);
|
QTableViewPrivate::SearchDirection::Decreasing);
|
||||||
break;
|
break;
|
||||||
case MovePageUp: {
|
case MovePageUp: {
|
||||||
|
@ -46,6 +46,7 @@
|
|||||||
#include "qstyleoption.h"
|
#include "qstyleoption.h"
|
||||||
#include "private/qstyle_p.h"
|
#include "private/qstyle_p.h"
|
||||||
#include "private/qguiapplication_p.h"
|
#include "private/qguiapplication_p.h"
|
||||||
|
#include <qpa/qplatformtheme.h>
|
||||||
#ifndef QT_NO_DEBUG
|
#ifndef QT_NO_DEBUG
|
||||||
#include "qdebug.h"
|
#include "qdebug.h"
|
||||||
#endif
|
#endif
|
||||||
@ -2447,6 +2448,13 @@ void QStyle::setProxy(QStyle *style)
|
|||||||
d->proxyStyle = 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
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
#include "moc_qstyle.cpp"
|
#include "moc_qstyle.cpp"
|
||||||
|
@ -67,6 +67,9 @@ class QStylePrivate: public QObjectPrivate
|
|||||||
public:
|
public:
|
||||||
inline QStylePrivate()
|
inline QStylePrivate()
|
||||||
: layoutSpacingIndex(-1), proxyStyle(nullptr) {}
|
: layoutSpacingIndex(-1), proxyStyle(nullptr) {}
|
||||||
|
|
||||||
|
static bool useFullScreenForPopup();
|
||||||
|
|
||||||
mutable int layoutSpacingIndex;
|
mutable int layoutSpacingIndex;
|
||||||
QStyle *proxyStyle;
|
QStyle *proxyStyle;
|
||||||
};
|
};
|
||||||
|
@ -80,6 +80,7 @@
|
|||||||
#if QT_CONFIG(effects)
|
#if QT_CONFIG(effects)
|
||||||
# include <private/qeffects_p.h>
|
# include <private/qeffects_p.h>
|
||||||
#endif
|
#endif
|
||||||
|
#include <private/qstyle_p.h>
|
||||||
#ifndef QT_NO_ACCESSIBILITY
|
#ifndef QT_NO_ACCESSIBILITY
|
||||||
#include "qaccessible.h"
|
#include "qaccessible.h"
|
||||||
#endif
|
#endif
|
||||||
@ -261,16 +262,11 @@ void QComboBoxPrivate::_q_modelDestroyed()
|
|||||||
model = QAbstractItemModelPrivate::staticEmptyModel();
|
model = QAbstractItemModelPrivate::staticEmptyModel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//Windows and KDE allows menus to cover the taskbar, while GNOME and Mac don't
|
|
||||||
QRect QComboBoxPrivate::popupGeometry(int screen) const
|
QRect QComboBoxPrivate::popupGeometry(int screen) const
|
||||||
{
|
{
|
||||||
bool useFullScreenForPopupMenu = false;
|
return QStylePrivate::useFullScreenForPopup()
|
||||||
if (const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme())
|
? QDesktopWidgetPrivate::screenGeometry(screen)
|
||||||
useFullScreenForPopupMenu = theme->themeHint(QPlatformTheme::UseFullScreenForPopupMenu).toBool();
|
: QDesktopWidgetPrivate::availableGeometry(screen);
|
||||||
return useFullScreenForPopupMenu ?
|
|
||||||
QDesktopWidgetPrivate::screenGeometry(screen) :
|
|
||||||
QDesktopWidgetPrivate::availableGeometry(screen);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool QComboBoxPrivate::updateHoverControl(const QPoint &pos)
|
bool QComboBoxPrivate::updateHoverControl(const QPoint &pos)
|
||||||
|
@ -78,6 +78,7 @@
|
|||||||
#include <private/qguiapplication_p.h>
|
#include <private/qguiapplication_p.h>
|
||||||
#include <qpa/qplatformtheme.h>
|
#include <qpa/qplatformtheme.h>
|
||||||
#include <private/qdesktopwidget_p.h>
|
#include <private/qdesktopwidget_p.h>
|
||||||
|
#include <private/qstyle_p.h>
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
@ -307,29 +308,26 @@ int QMenuPrivate::scrollerHeight() const
|
|||||||
return qMax(QApplication::globalStrut().height(), q->style()->pixelMetric(QStyle::PM_MenuScrollerHeight, 0, q));
|
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
|
QRect QMenuPrivate::popupGeometry() const
|
||||||
{
|
{
|
||||||
Q_Q(const QMenu);
|
Q_Q(const QMenu);
|
||||||
if (!tornoff && // Torn-off menus are different
|
return useFullScreenForPopup()
|
||||||
QGuiApplicationPrivate::platformTheme() &&
|
? QDesktopWidgetPrivate::screenGeometry(q)
|
||||||
QGuiApplicationPrivate::platformTheme()->themeHint(QPlatformTheme::UseFullScreenForPopupMenu).toBool()) {
|
: QDesktopWidgetPrivate::availableGeometry(q);
|
||||||
return QDesktopWidgetPrivate::screenGeometry(q);
|
|
||||||
} else {
|
|
||||||
return QDesktopWidgetPrivate::availableGeometry(q);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//Windows and KDE allow menus to cover the taskbar, while GNOME and Mac don't
|
|
||||||
QRect QMenuPrivate::popupGeometry(int screen) const
|
QRect QMenuPrivate::popupGeometry(int screen) const
|
||||||
{
|
{
|
||||||
if (!tornoff && // Torn-off menus are different
|
return useFullScreenForPopup()
|
||||||
QGuiApplicationPrivate::platformTheme() &&
|
? QDesktopWidgetPrivate::screenGeometry(screen)
|
||||||
QGuiApplicationPrivate::platformTheme()->themeHint(QPlatformTheme::UseFullScreenForPopupMenu).toBool()) {
|
: QDesktopWidgetPrivate::availableGeometry(screen);
|
||||||
return QDesktopWidgetPrivate::screenGeometry(screen);
|
|
||||||
} else {
|
|
||||||
return QDesktopWidgetPrivate::availableGeometry(screen);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QVector<QPointer<QWidget> > QMenuPrivate::calcCausedStack() const
|
QVector<QPointer<QWidget> > QMenuPrivate::calcCausedStack() const
|
||||||
|
@ -349,6 +349,7 @@ public:
|
|||||||
void updateActionRects(const QRect &screen) const;
|
void updateActionRects(const QRect &screen) const;
|
||||||
QRect popupGeometry() const;
|
QRect popupGeometry() const;
|
||||||
QRect popupGeometry(int screen) const;
|
QRect popupGeometry(int screen) const;
|
||||||
|
bool useFullScreenForPopup() const;
|
||||||
int getLastVisibleAction() const;
|
int getLastVisibleAction() const;
|
||||||
|
|
||||||
//selection
|
//selection
|
||||||
|
@ -47,6 +47,7 @@ class tst_QUrl : public QObject
|
|||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void initTestCase();
|
void initTestCase();
|
||||||
|
void cleanupTestCase();
|
||||||
void effectiveTLDs_data();
|
void effectiveTLDs_data();
|
||||||
void effectiveTLDs();
|
void effectiveTLDs();
|
||||||
void getSetCheck();
|
void getSetCheck();
|
||||||
@ -188,6 +189,7 @@ private slots:
|
|||||||
private:
|
private:
|
||||||
void testThreadingHelper();
|
void testThreadingHelper();
|
||||||
|
|
||||||
|
const QString m_currentPath = QDir::currentPath();
|
||||||
QTemporaryDir m_tempDir;
|
QTemporaryDir m_tempDir;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -196,6 +198,12 @@ void tst_QUrl::initTestCase()
|
|||||||
QVERIFY2(m_tempDir.isValid(), qPrintable(m_tempDir.errorString()));
|
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
|
// Testing get/set functions
|
||||||
void tst_QUrl::getSetCheck()
|
void tst_QUrl::getSetCheck()
|
||||||
{
|
{
|
||||||
|
@ -40,6 +40,13 @@ struct MyStruct
|
|||||||
int i;
|
int i;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class MyGadget
|
||||||
|
{
|
||||||
|
Q_GADGET
|
||||||
|
public:
|
||||||
|
Q_INVOKABLE MyGadget() {}
|
||||||
|
};
|
||||||
|
|
||||||
namespace MyNamespace {
|
namespace MyNamespace {
|
||||||
// Used in tst_QMetaObject::checkScope
|
// Used in tst_QMetaObject::checkScope
|
||||||
class MyClass : public QObject
|
class MyClass : public QObject
|
||||||
@ -1208,6 +1215,12 @@ void tst_QMetaObject::invokeMetaConstructor()
|
|||||||
QCOMPARE(obj2->parent(), (QObject*)&obj);
|
QCOMPARE(obj2->parent(), (QObject*)&obj);
|
||||||
QVERIFY(qobject_cast<NamespaceWithConstructibleClass::ConstructibleClass*>(obj2) != 0);
|
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()
|
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)
|
Http2Server::Http2Server(H2Type type, const Http2::RawSettings &ss, const Http2::RawSettings &cs)
|
||||||
: serverSettings(ss),
|
: connectionType(type),
|
||||||
expectedClientSettings(cs),
|
serverSettings(ss),
|
||||||
clearTextHTTP2(h2c)
|
expectedClientSettings(cs)
|
||||||
{
|
{
|
||||||
|
#if !QT_CONFIG(ssl)
|
||||||
|
Q_ASSERT(type != H2Type::h2Alpn && type != H2Type::h2Direct);
|
||||||
|
#endif
|
||||||
|
|
||||||
responseBody = "<html>\n"
|
responseBody = "<html>\n"
|
||||||
"<head>\n"
|
"<head>\n"
|
||||||
"<title>Sample \"Hello, World\" Application</title>\n"
|
"<title>Sample \"Hello, World\" Application</title>\n"
|
||||||
@ -129,15 +133,15 @@ void Http2Server::redirectOpenStream(quint16 port)
|
|||||||
targetPort = port;
|
targetPort = port;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Http2Server::isClearText() const
|
||||||
|
{
|
||||||
|
return connectionType == H2Type::h2c || connectionType == H2Type::h2cDirect;
|
||||||
|
}
|
||||||
|
|
||||||
void Http2Server::startServer()
|
void Http2Server::startServer()
|
||||||
{
|
{
|
||||||
#ifdef QT_NO_SSL
|
|
||||||
// Let the test fail with timeout.
|
|
||||||
if (!clearTextHTTP2)
|
|
||||||
return;
|
|
||||||
#endif
|
|
||||||
if (listen()) {
|
if (listen()) {
|
||||||
if (clearTextHTTP2)
|
if (isClearText())
|
||||||
authority = QStringLiteral("127.0.0.1:%1").arg(serverPort()).toLatin1();
|
authority = QStringLiteral("127.0.0.1:%1").arg(serverPort()).toLatin1();
|
||||||
emit serverStarted(serverPort());
|
emit serverStarted(serverPort());
|
||||||
}
|
}
|
||||||
@ -146,7 +150,7 @@ void Http2Server::startServer()
|
|||||||
bool Http2Server::sendProtocolSwitchReply()
|
bool Http2Server::sendProtocolSwitchReply()
|
||||||
{
|
{
|
||||||
Q_ASSERT(socket);
|
Q_ASSERT(socket);
|
||||||
Q_ASSERT(clearTextHTTP2 && upgradeProtocol);
|
Q_ASSERT(connectionType == H2Type::h2c);
|
||||||
// The first and the last HTTP/1.1 response we send:
|
// The first and the last HTTP/1.1 response we send:
|
||||||
const char response[] = "HTTP/1.1 101 Switching Protocols\r\n"
|
const char response[] = "HTTP/1.1 101 Switching Protocols\r\n"
|
||||||
"Connection: Upgrade\r\n"
|
"Connection: Upgrade\r\n"
|
||||||
@ -262,25 +266,28 @@ void Http2Server::sendWINDOW_UPDATE(quint32 streamID, quint32 delta)
|
|||||||
|
|
||||||
void Http2Server::incomingConnection(qintptr socketDescriptor)
|
void Http2Server::incomingConnection(qintptr socketDescriptor)
|
||||||
{
|
{
|
||||||
if (clearTextHTTP2) {
|
if (isClearText()) {
|
||||||
socket.reset(new QTcpSocket);
|
socket.reset(new QTcpSocket);
|
||||||
const bool set = socket->setSocketDescriptor(socketDescriptor);
|
const bool set = socket->setSocketDescriptor(socketDescriptor);
|
||||||
Q_ASSERT(set);
|
Q_ASSERT(set);
|
||||||
// Stop listening:
|
// Stop listening:
|
||||||
close();
|
close();
|
||||||
upgradeProtocol = true;
|
upgradeProtocol = connectionType == H2Type::h2c;
|
||||||
QMetaObject::invokeMethod(this, "connectionEstablished",
|
QMetaObject::invokeMethod(this, "connectionEstablished",
|
||||||
Qt::QueuedConnection);
|
Qt::QueuedConnection);
|
||||||
} else {
|
} else {
|
||||||
#ifndef QT_NO_SSL
|
#if QT_CONFIG(ssl)
|
||||||
socket.reset(new QSslSocket);
|
socket.reset(new QSslSocket);
|
||||||
QSslSocket *sslSocket = static_cast<QSslSocket *>(socket.data());
|
QSslSocket *sslSocket = static_cast<QSslSocket *>(socket.data());
|
||||||
|
|
||||||
|
if (connectionType == H2Type::h2Alpn) {
|
||||||
// Add HTTP2 as supported protocol:
|
// Add HTTP2 as supported protocol:
|
||||||
auto conf = QSslConfiguration::defaultConfiguration();
|
auto conf = QSslConfiguration::defaultConfiguration();
|
||||||
auto protos = conf.allowedNextProtocols();
|
auto protos = conf.allowedNextProtocols();
|
||||||
protos.prepend(QSslConfiguration::ALPNProtocolHTTP2);
|
protos.prepend(QSslConfiguration::ALPNProtocolHTTP2);
|
||||||
conf.setAllowedNextProtocols(protos);
|
conf.setAllowedNextProtocols(protos);
|
||||||
sslSocket->setSslConfiguration(conf);
|
sslSocket->setSslConfiguration(conf);
|
||||||
|
}
|
||||||
// SSL-related setup ...
|
// SSL-related setup ...
|
||||||
sslSocket->setPeerVerifyMode(QSslSocket::VerifyNone);
|
sslSocket->setPeerVerifyMode(QSslSocket::VerifyNone);
|
||||||
sslSocket->setProtocol(QSsl::TlsV1_2OrLater);
|
sslSocket->setProtocol(QSsl::TlsV1_2OrLater);
|
||||||
@ -299,7 +306,7 @@ void Http2Server::incomingConnection(qintptr socketDescriptor)
|
|||||||
connect(sslSocket, SIGNAL(encrypted()), this, SLOT(connectionEstablished()));
|
connect(sslSocket, SIGNAL(encrypted()), this, SLOT(connectionEstablished()));
|
||||||
sslSocket->startServerEncryption();
|
sslSocket->startServerEncryption();
|
||||||
#else
|
#else
|
||||||
Q_UNREACHABLE();
|
Q_ASSERT(0);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -377,7 +384,7 @@ void Http2Server::connectionEstablished()
|
|||||||
{
|
{
|
||||||
using namespace Http2;
|
using namespace Http2;
|
||||||
|
|
||||||
if (testingGOAWAY && !clearTextHTTP2)
|
if (testingGOAWAY && !isClearText())
|
||||||
return triggerGOAWAYEmulation();
|
return triggerGOAWAYEmulation();
|
||||||
|
|
||||||
// For clearTextHTTP2 we first have to respond with 'protocol switch'
|
// For clearTextHTTP2 we first have to respond with 'protocol switch'
|
||||||
@ -392,7 +399,7 @@ void Http2Server::connectionEstablished()
|
|||||||
waitingClientSettings = false;
|
waitingClientSettings = false;
|
||||||
settingsSent = false;
|
settingsSent = false;
|
||||||
|
|
||||||
if (clearTextHTTP2) {
|
if (connectionType == H2Type::h2c) {
|
||||||
requestLine.clear();
|
requestLine.clear();
|
||||||
// Now we have to handle HTTP/1.1 request. We use Get/Post in our test,
|
// Now we have to handle HTTP/1.1 request. We use Get/Post in our test,
|
||||||
// so set requestType to something unsupported:
|
// so set requestType to something unsupported:
|
||||||
@ -818,7 +825,7 @@ void Http2Server::sendResponse(quint32 streamID, bool emptyBody)
|
|||||||
Q_ASSERT(targetPort);
|
Q_ASSERT(targetPort);
|
||||||
header.push_back({":status", "308"});
|
header.push_back({":status", "308"});
|
||||||
const QString url("%1://localhost:%2/");
|
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()});
|
QString::number(targetPort)).toLatin1()});
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
@ -62,21 +62,32 @@ public:
|
|||||||
Q_DECLARE_PRIVATE(Http11Reply)
|
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
|
class Http2Server : public QTcpServer
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
Http2Server(bool clearText, const Http2::RawSettings &serverSettings,
|
|
||||||
|
Http2Server(H2Type type, const Http2::RawSettings &serverSettings,
|
||||||
const Http2::RawSettings &clientSettings);
|
const Http2::RawSettings &clientSettings);
|
||||||
|
|
||||||
~Http2Server();
|
~Http2Server();
|
||||||
|
|
||||||
|
|
||||||
// To be called before server started:
|
// To be called before server started:
|
||||||
void enablePushPromise(bool enabled, const QByteArray &path = QByteArray());
|
void enablePushPromise(bool enabled, const QByteArray &path = QByteArray());
|
||||||
void setResponseBody(const QByteArray &body);
|
void setResponseBody(const QByteArray &body);
|
||||||
void emulateGOAWAY(int timeout);
|
void emulateGOAWAY(int timeout);
|
||||||
void redirectOpenStream(quint16 targetPort);
|
void redirectOpenStream(quint16 targetPort);
|
||||||
|
|
||||||
|
bool isClearText() const;
|
||||||
|
|
||||||
// Invokables, since we can call them from the main thread,
|
// Invokables, since we can call them from the main thread,
|
||||||
// but server (can) work on its own thread.
|
// but server (can) work on its own thread.
|
||||||
Q_INVOKABLE void startServer();
|
Q_INVOKABLE void startServer();
|
||||||
@ -129,6 +140,7 @@ private:
|
|||||||
|
|
||||||
QScopedPointer<QAbstractSocket> socket;
|
QScopedPointer<QAbstractSocket> socket;
|
||||||
|
|
||||||
|
H2Type connectionType = H2Type::h2Alpn;
|
||||||
// Connection preface:
|
// Connection preface:
|
||||||
bool waitingClientPreface = false;
|
bool waitingClientPreface = false;
|
||||||
bool waitingClientSettings = false;
|
bool waitingClientSettings = false;
|
||||||
@ -170,7 +182,6 @@ private:
|
|||||||
quint32 streamRecvWindowSize = Http2::defaultSessionWindowSize;
|
quint32 streamRecvWindowSize = Http2::defaultSessionWindowSize;
|
||||||
|
|
||||||
QByteArray responseBody;
|
QByteArray responseBody;
|
||||||
bool clearTextHTTP2 = false;
|
|
||||||
bool pushPromiseEnabled = false;
|
bool pushPromiseEnabled = false;
|
||||||
quint32 lastPromisedStream = 0;
|
quint32 lastPromisedStream = 0;
|
||||||
QByteArray pushPath;
|
QByteArray pushPath;
|
||||||
|
@ -60,6 +60,9 @@ const bool clearTextHTTP2 = false;
|
|||||||
const bool clearTextHTTP2 = true;
|
const bool clearTextHTTP2 = true;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
Q_DECLARE_METATYPE(H2Type)
|
||||||
|
Q_DECLARE_METATYPE(QNetworkRequest::Attribute)
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
class tst_Http2 : public QObject
|
class tst_Http2 : public QObject
|
||||||
@ -70,6 +73,7 @@ public:
|
|||||||
~tst_Http2();
|
~tst_Http2();
|
||||||
private slots:
|
private slots:
|
||||||
// Tests:
|
// Tests:
|
||||||
|
void singleRequest_data();
|
||||||
void singleRequest();
|
void singleRequest();
|
||||||
void multipleRequests();
|
void multipleRequests();
|
||||||
void flowControlClientSide();
|
void flowControlClientSide();
|
||||||
@ -101,13 +105,13 @@ private:
|
|||||||
// small payload.
|
// small payload.
|
||||||
void runEventLoop(int ms = 5000);
|
void runEventLoop(int ms = 5000);
|
||||||
void stopEventLoop();
|
void stopEventLoop();
|
||||||
Http2Server *newServer(const Http2::RawSettings &serverSettings,
|
Http2Server *newServer(const Http2::RawSettings &serverSettings, H2Type connectionType,
|
||||||
const Http2::ProtocolParameters &clientSettings = {});
|
const Http2::ProtocolParameters &clientSettings = {});
|
||||||
// Send a get or post request, depending on a payload (empty or not).
|
// Send a get or post request, depending on a payload (empty or not).
|
||||||
void sendRequest(int streamNumber,
|
void sendRequest(int streamNumber,
|
||||||
QNetworkRequest::Priority priority = QNetworkRequest::NormalPriority,
|
QNetworkRequest::Priority priority = QNetworkRequest::NormalPriority,
|
||||||
const QByteArray &payload = QByteArray());
|
const QByteArray &payload = QByteArray());
|
||||||
QUrl requestUrl() const;
|
QUrl requestUrl(H2Type connnectionType) const;
|
||||||
|
|
||||||
quint16 serverPort = 0;
|
quint16 serverPort = 0;
|
||||||
QThread *workerThread = nullptr;
|
QThread *workerThread = nullptr;
|
||||||
@ -144,6 +148,11 @@ struct ServerDeleter
|
|||||||
|
|
||||||
using ServerPtr = QScopedPointer<Http2Server, ServerDeleter>;
|
using ServerPtr = QScopedPointer<Http2Server, ServerDeleter>;
|
||||||
|
|
||||||
|
H2Type defaultConnectionType()
|
||||||
|
{
|
||||||
|
return clearTextHTTP2 ? H2Type::h2c : H2Type::h2Alpn;
|
||||||
|
}
|
||||||
|
|
||||||
} // unnamed namespace
|
} // unnamed namespace
|
||||||
|
|
||||||
tst_Http2::tst_Http2()
|
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()
|
void tst_Http2::singleRequest()
|
||||||
{
|
{
|
||||||
clearHTTP2State();
|
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;
|
serverPort = 0;
|
||||||
nRequests = 1;
|
nRequests = 1;
|
||||||
|
|
||||||
ServerPtr srv(newServer(defaultServerSettings));
|
QFETCH(const H2Type, connectionType);
|
||||||
|
ServerPtr srv(newServer(defaultServerSettings, connectionType));
|
||||||
|
|
||||||
QMetaObject::invokeMethod(srv.data(), "startServer", Qt::QueuedConnection);
|
QMetaObject::invokeMethod(srv.data(), "startServer", Qt::QueuedConnection);
|
||||||
runEventLoop();
|
runEventLoop();
|
||||||
|
|
||||||
QVERIFY(serverPort != 0);
|
QVERIFY(serverPort != 0);
|
||||||
|
|
||||||
auto url = requestUrl();
|
auto url = requestUrl(connectionType);
|
||||||
url.setPath("/index.html");
|
url.setPath("/index.html");
|
||||||
|
|
||||||
QNetworkRequest request(url);
|
QNetworkRequest request(url);
|
||||||
request.setAttribute(QNetworkRequest::HTTP2AllowedAttribute, QVariant(true));
|
QFETCH(const QNetworkRequest::Attribute, h2Attribute);
|
||||||
|
request.setAttribute(h2Attribute, QVariant(true));
|
||||||
|
|
||||||
auto reply = manager.get(request);
|
auto reply = manager.get(request);
|
||||||
connect(reply, &QNetworkReply::finished, this, &tst_Http2::replyFinished);
|
connect(reply, &QNetworkReply::finished, this, &tst_Http2::replyFinished);
|
||||||
@ -208,7 +251,7 @@ void tst_Http2::multipleRequests()
|
|||||||
serverPort = 0;
|
serverPort = 0;
|
||||||
nRequests = 10;
|
nRequests = 10;
|
||||||
|
|
||||||
ServerPtr srv(newServer(defaultServerSettings));
|
ServerPtr srv(newServer(defaultServerSettings, defaultConnectionType()));
|
||||||
|
|
||||||
QMetaObject::invokeMethod(srv.data(), "startServer", Qt::QueuedConnection);
|
QMetaObject::invokeMethod(srv.data(), "startServer", Qt::QueuedConnection);
|
||||||
|
|
||||||
@ -259,7 +302,7 @@ void tst_Http2::flowControlClientSide()
|
|||||||
manager.setProperty(Http2::http2ParametersPropertyName, QVariant::fromValue(params));
|
manager.setProperty(Http2::http2ParametersPropertyName, QVariant::fromValue(params));
|
||||||
|
|
||||||
const Http2::RawSettings serverSettings = {{Settings::MAX_CONCURRENT_STREAMS_ID, quint32(3)}};
|
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');
|
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}};
|
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');
|
const QByteArray payload(int(Http2::defaultSessionWindowSize * 500), 'x');
|
||||||
|
|
||||||
@ -336,7 +379,7 @@ void tst_Http2::pushPromise()
|
|||||||
params.settingsFrameData[Settings::ENABLE_PUSH_ID] = 1;
|
params.settingsFrameData[Settings::ENABLE_PUSH_ID] = 1;
|
||||||
manager.setProperty(Http2::http2ParametersPropertyName, QVariant::fromValue(params));
|
manager.setProperty(Http2::http2ParametersPropertyName, QVariant::fromValue(params));
|
||||||
|
|
||||||
ServerPtr srv(newServer(defaultServerSettings, params));
|
ServerPtr srv(newServer(defaultServerSettings, defaultConnectionType(), params));
|
||||||
srv->enablePushPromise(true, QByteArray("/script.js"));
|
srv->enablePushPromise(true, QByteArray("/script.js"));
|
||||||
|
|
||||||
QMetaObject::invokeMethod(srv.data(), "startServer", Qt::QueuedConnection);
|
QMetaObject::invokeMethod(srv.data(), "startServer", Qt::QueuedConnection);
|
||||||
@ -344,7 +387,7 @@ void tst_Http2::pushPromise()
|
|||||||
|
|
||||||
QVERIFY(serverPort != 0);
|
QVERIFY(serverPort != 0);
|
||||||
|
|
||||||
auto url = requestUrl();
|
auto url = requestUrl(defaultConnectionType());
|
||||||
url.setPath("/index.html");
|
url.setPath("/index.html");
|
||||||
|
|
||||||
QNetworkRequest request(url);
|
QNetworkRequest request(url);
|
||||||
@ -410,14 +453,14 @@ void tst_Http2::goaway()
|
|||||||
serverPort = 0;
|
serverPort = 0;
|
||||||
nRequests = 3;
|
nRequests = 3;
|
||||||
|
|
||||||
ServerPtr srv(newServer(defaultServerSettings));
|
ServerPtr srv(newServer(defaultServerSettings, defaultConnectionType()));
|
||||||
srv->emulateGOAWAY(responseTimeoutMS);
|
srv->emulateGOAWAY(responseTimeoutMS);
|
||||||
QMetaObject::invokeMethod(srv.data(), "startServer", Qt::QueuedConnection);
|
QMetaObject::invokeMethod(srv.data(), "startServer", Qt::QueuedConnection);
|
||||||
runEventLoop();
|
runEventLoop();
|
||||||
|
|
||||||
QVERIFY(serverPort != 0);
|
QVERIFY(serverPort != 0);
|
||||||
|
|
||||||
auto url = requestUrl();
|
auto url = requestUrl(defaultConnectionType());
|
||||||
// We have to store these replies, so that we can check errors later.
|
// We have to store these replies, so that we can check errors later.
|
||||||
std::vector<QNetworkReply *> replies(nRequests);
|
std::vector<QNetworkReply *> replies(nRequests);
|
||||||
for (int i = 0; i < nRequests; ++i) {
|
for (int i = 0; i < nRequests; ++i) {
|
||||||
@ -457,7 +500,7 @@ void tst_Http2::earlyResponse()
|
|||||||
serverPort = 0;
|
serverPort = 0;
|
||||||
nRequests = 1;
|
nRequests = 1;
|
||||||
|
|
||||||
ServerPtr targetServer(newServer(defaultServerSettings));
|
ServerPtr targetServer(newServer(defaultServerSettings, defaultConnectionType()));
|
||||||
|
|
||||||
QMetaObject::invokeMethod(targetServer.data(), "startServer", Qt::QueuedConnection);
|
QMetaObject::invokeMethod(targetServer.data(), "startServer", Qt::QueuedConnection);
|
||||||
runEventLoop();
|
runEventLoop();
|
||||||
@ -467,7 +510,7 @@ void tst_Http2::earlyResponse()
|
|||||||
const quint16 targetPort = serverPort;
|
const quint16 targetPort = serverPort;
|
||||||
serverPort = 0;
|
serverPort = 0;
|
||||||
|
|
||||||
ServerPtr redirector(newServer(defaultServerSettings));
|
ServerPtr redirector(newServer(defaultServerSettings, defaultConnectionType()));
|
||||||
redirector->redirectOpenStream(targetPort);
|
redirector->redirectOpenStream(targetPort);
|
||||||
|
|
||||||
QMetaObject::invokeMethod(redirector.data(), "startServer", Qt::QueuedConnection);
|
QMetaObject::invokeMethod(redirector.data(), "startServer", Qt::QueuedConnection);
|
||||||
@ -507,11 +550,11 @@ void tst_Http2::stopEventLoop()
|
|||||||
eventLoop.exitLoop();
|
eventLoop.exitLoop();
|
||||||
}
|
}
|
||||||
|
|
||||||
Http2Server *tst_Http2::newServer(const Http2::RawSettings &serverSettings,
|
Http2Server *tst_Http2::newServer(const Http2::RawSettings &serverSettings, H2Type connectionType,
|
||||||
const Http2::ProtocolParameters &clientSettings)
|
const Http2::ProtocolParameters &clientSettings)
|
||||||
{
|
{
|
||||||
using namespace Http2;
|
using namespace Http2;
|
||||||
auto srv = new Http2Server(clearTextHTTP2, serverSettings,
|
auto srv = new Http2Server(connectionType, serverSettings,
|
||||||
clientSettings.settingsFrameData);
|
clientSettings.settingsFrameData);
|
||||||
|
|
||||||
using Srv = Http2Server;
|
using Srv = Http2Server;
|
||||||
@ -536,7 +579,7 @@ void tst_Http2::sendRequest(int streamNumber,
|
|||||||
QNetworkRequest::Priority priority,
|
QNetworkRequest::Priority priority,
|
||||||
const QByteArray &payload)
|
const QByteArray &payload)
|
||||||
{
|
{
|
||||||
auto url = requestUrl();
|
auto url = requestUrl(defaultConnectionType());
|
||||||
url.setPath(QString("/stream%1.html").arg(streamNumber));
|
url.setPath(QString("/stream%1.html").arg(streamNumber));
|
||||||
|
|
||||||
QNetworkRequest request(url);
|
QNetworkRequest request(url);
|
||||||
@ -555,10 +598,24 @@ void tst_Http2::sendRequest(int streamNumber,
|
|||||||
connect(reply, &QNetworkReply::finished, this, &tst_Http2::replyFinished);
|
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"));
|
static auto url = QUrl(QLatin1String(clearTextHTTP2 ? "http://127.0.0.1" : "https://127.0.0.1"));
|
||||||
url.setPort(serverPort);
|
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;
|
return url;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user