diff options
author | Liang Qi <liang.qi@qt.io> | 2019-04-11 07:47:21 +0200 |
---|---|---|
committer | Liang Qi <liang.qi@qt.io> | 2019-04-11 07:47:21 +0200 |
commit | c7af193d2e49e9f10b86262e63d8d13abf72b5cf (patch) | |
tree | 7ca5d4ba83888bb5ad4d9b0141e5c62f8a5138f2 /src/3rdparty | |
parent | 235ac95520a0fc2c822dedce7358e3c64a764255 (diff) | |
parent | 63e88f60a769f2535945db0e1cabb9815ff45a77 (diff) |
Merge remote-tracking branch 'origin/5.13' into dev
Conflicts:
src/widgets/styles/qstyle_p.h
Change-Id: I0e6e856bd6628da1135b3ba674dddffabbeb5c09
Diffstat (limited to 'src/3rdparty')
-rw-r--r-- | src/3rdparty/tinycbor/src/cbor.h | 4 | ||||
-rw-r--r-- | src/3rdparty/tinycbor/src/cborencoder.c | 24 | ||||
-rw-r--r-- | src/3rdparty/tinycbor/src/cborparser.c | 2 | ||||
-rw-r--r-- | src/3rdparty/tinycbor/src/compilersupport_p.h | 2 | ||||
-rw-r--r-- | src/3rdparty/tinycbor/tests/encoder/data.cpp | 36 | ||||
-rw-r--r-- | src/3rdparty/tinycbor/tests/encoder/tst_encoder.cpp | 125 | ||||
-rw-r--r-- | src/3rdparty/tinycbor/tests/parser/tst_parser.cpp | 377 |
7 files changed, 457 insertions, 113 deletions
diff --git a/src/3rdparty/tinycbor/src/cbor.h b/src/3rdparty/tinycbor/src/cbor.h index 5c7ba74e39..3672bd0d98 100644 --- a/src/3rdparty/tinycbor/src/cbor.h +++ b/src/3rdparty/tinycbor/src/cbor.h @@ -257,6 +257,7 @@ CBOR_INLINE_API CborError cbor_encode_undefined(CborEncoder *encoder) CBOR_INLINE_API CborError cbor_encode_half_float(CborEncoder *encoder, const void *value) { return cbor_encode_floating_point(encoder, CborHalfFloatType, value); } +CBOR_API CborError cbor_encode_float_as_half_float(CborEncoder *encoder, float value); CBOR_INLINE_API CborError cbor_encode_float(CborEncoder *encoder, float value) { return cbor_encode_floating_point(encoder, CborFloatType, &value); } CBOR_INLINE_API CborError cbor_encode_double(CborEncoder *encoder, double value) @@ -593,12 +594,13 @@ CBOR_API CborError cbor_value_map_find_value(const CborValue *map, const char *s /* Floating point */ CBOR_INLINE_API bool cbor_value_is_half_float(const CborValue *value) { return value->type == CborHalfFloatType; } +CBOR_API CborError cbor_value_get_half_float_as_float(const CborValue *value, float *result); CBOR_INLINE_API CborError cbor_value_get_half_float(const CborValue *value, void *result) { assert(cbor_value_is_half_float(value)); assert((value->flags & CborIteratorFlag_IntegerValueTooLarge) == 0); - /* size has been computed already */ + /* size has already been computed */ memcpy(result, &value->extra, sizeof(value->extra)); return CborNoError; } diff --git a/src/3rdparty/tinycbor/src/cborencoder.c b/src/3rdparty/tinycbor/src/cborencoder.c index 52a4025be1..38804cfa6f 100644 --- a/src/3rdparty/tinycbor/src/cborencoder.c +++ b/src/3rdparty/tinycbor/src/cborencoder.c @@ -76,7 +76,7 @@ * \code * uint8_t buf[16]; * CborEncoder encoder, mapEncoder; - * cbor_encoder_init(&encoder, &buf, sizeof(buf), 0); + * cbor_encoder_init(&encoder, buf, sizeof(buf), 0); * cbor_encoder_create_map(&encoder, &mapEncoder, 1); * cbor_encode_text_stringz(&mapEncoder, "foo"); * cbor_encode_boolean(&mapEncoder, some_value); @@ -115,7 +115,7 @@ * uint8_t buf[16]; * CborError err; * CborEncoder encoder, mapEncoder; - * cbor_encoder_init(&encoder, &buf, sizeof(buf), 0); + * cbor_encoder_init(&encoder, buf, sizeof(buf), 0); * err = cbor_encoder_create_map(&encoder, &mapEncoder, 1); * if (!err) * return err; @@ -155,7 +155,7 @@ * goto error; * buf = nbuf; * - * cbor_encoder_init(&encoder, &buf, size, 0); + * cbor_encoder_init(&encoder, buf, size, 0); * err = cbor_encoder_create_array(&encoder, &arrayEncoder, n); * cbor_assert(err); // can't fail, the buffer is always big enough * @@ -411,7 +411,7 @@ CborError cbor_encode_simple_value(CborEncoder *encoder, uint8_t value) * This function is useful for code that needs to pass through floating point * values but does not wish to have the actual floating-point code. * - * \sa cbor_encode_half_float, cbor_encode_float, cbor_encode_double + * \sa cbor_encode_half_float, cbor_encode_float_as_half_float, cbor_encode_float, cbor_encode_double */ CborError cbor_encode_floating_point(CborEncoder *encoder, CborType fpType, const void *value) { @@ -622,12 +622,24 @@ CborError cbor_encoder_close_container(CborEncoder *encoder, const CborEncoder * */ /** + * \fn CborError cbor_encode_float_as_half_float(CborEncoder *encoder, float value) + * + * Convert the IEEE 754 single-precision (32-bit) floating point value \a value + * to the IEEE 754 half-precision (16-bit) floating point value and append it + * to the CBOR stream provided by \a encoder. + * The \a value should be in the range of the IEEE 754 half-precision floating point type, + * INFINITY, -INFINITY, or NAN, otherwise the behavior of this function is undefined. + * + * \sa cbor_encode_floating_point(), cbor_encode_float(), cbor_encode_double() + */ + +/** * \fn CborError cbor_encode_float(CborEncoder *encoder, float value) * * Appends the IEEE 754 single-precision (32-bit) floating point value \a value * to the CBOR stream provided by \a encoder. * - * \sa cbor_encode_floating_point(), cbor_encode_half_float(), cbor_encode_double() + * \sa cbor_encode_floating_point(), cbor_encode_half_float(), cbor_encode_float_as_half_float(), cbor_encode_double() */ /** @@ -636,7 +648,7 @@ CborError cbor_encoder_close_container(CborEncoder *encoder, const CborEncoder * * Appends the IEEE 754 double-precision (64-bit) floating point value \a value * to the CBOR stream provided by \a encoder. * - * \sa cbor_encode_floating_point(), cbor_encode_half_float(), cbor_encode_float() + * \sa cbor_encode_floating_point(), cbor_encode_half_float(), cbor_encode_float_as_half_float(), cbor_encode_float() */ /** diff --git a/src/3rdparty/tinycbor/src/cborparser.c b/src/3rdparty/tinycbor/src/cborparser.c index 971230ea61..90a7d2ced6 100644 --- a/src/3rdparty/tinycbor/src/cborparser.c +++ b/src/3rdparty/tinycbor/src/cborparser.c @@ -1520,7 +1520,7 @@ error: * floating point, this function takes a \c{void *} as a parameter for the * storage area, which must be at least 16 bits wide. * - * \sa cbor_value_get_type(), cbor_value_is_valid(), cbor_value_is_half_float(), cbor_value_get_float() + * \sa cbor_value_get_type(), cbor_value_is_valid(), cbor_value_is_half_float(), cbor_value_get_half_float_as_float(), cbor_value_get_float() */ /** @} */ diff --git a/src/3rdparty/tinycbor/src/compilersupport_p.h b/src/3rdparty/tinycbor/src/compilersupport_p.h index 2b9491d34d..bd10efc9c7 100644 --- a/src/3rdparty/tinycbor/src/compilersupport_p.h +++ b/src/3rdparty/tinycbor/src/compilersupport_p.h @@ -106,7 +106,7 @@ # define cbor_ntohs __builtin_bswap16 # define cbor_htons __builtin_bswap16 # else -# define cbor_ntohs(x) (((uint16_t)x >> 8) | ((uint16_t)x << 8)) +# define cbor_ntohs(x) (((uint16_t)(x) >> 8) | ((uint16_t)(x) << 8)) # define cbor_htons cbor_ntohs # endif # else diff --git a/src/3rdparty/tinycbor/tests/encoder/data.cpp b/src/3rdparty/tinycbor/tests/encoder/data.cpp index c33fb605aa..8b00cfec1f 100644 --- a/src/3rdparty/tinycbor/tests/encoder/data.cpp +++ b/src/3rdparty/tinycbor/tests/encoder/data.cpp @@ -123,6 +123,42 @@ QVariant make_ilmap(const std::initializer_list<QPair<QVariant, QVariant>> &list return QVariant::fromValue(IndeterminateLengthMap(list)); } +void addHalfFloat() +{ + QTest::addColumn<QByteArray>("output"); + QTest::addColumn<unsigned>("rawInput"); + QTest::addColumn<double>("floatInput"); + + QTest::newRow("+0") << raw("\x00\x00") << 0U << 0.0; + QTest::newRow("-0") << raw("\x80\x00") << 0x8000U << 0.0; + + QTest::newRow("min.denorm") << raw("\x00\x01") << 1U << ldexp(1.0, -14) * ldexp(1.0, -10); + QTest::newRow("-min.denorm") << raw("\x80\x01") << 0x8001U << ldexp(-1.0, -14) * ldexp(1.0, -10); + + QTest::newRow("max.denorm") << raw("\x03\xff") << 0x03ffU << ldexp(1.0, -14) * (1.0 - ldexp(1.0, -10)); + QTest::newRow("-max.denorm") << raw("\x83\xff") << 0x83ffU << ldexp(-1.0, -14) * (1.0 - ldexp(1.0, -10)); + + QTest::newRow("min.norm") << raw("\x04\x00") << 0x0400U << ldexp(1.0, -14); + QTest::newRow("-min.norm") << raw("\x84\x00") << 0x8400U << ldexp(-1.0, -14); + + QTest::newRow("1.0") << raw("\x3c\x00") << 0x3c00U << 1.0; + QTest::newRow("-1.0") << raw("\xbc\x00") << 0xbc00U << -1.0; + + QTest::newRow("1.5") << raw("\x3e\x00") << 0x3e00U << 1.5; + QTest::newRow("-1.5") << raw("\xbe\x00") << 0xbe00U << -1.5; + + QTest::newRow("max") << raw("\x7b\xff") << 0x7bffU << ldexp(1.0, 15) * (2.0 - ldexp(1.0, -10)); + QTest::newRow("-max") << raw("\xfb\xff") << 0xfbffU << ldexp(-1.0, 15) * (2.0 - ldexp(1.0, -10)); + + QTest::newRow("inf") << raw("\x7c\x00") << 0x7c00U << myInf(); + QTest::newRow("-inf") << raw("\xfc\x00") << 0xfc00U << myNInf(); + + QTest::newRow("nan1") << raw("\x7c\x01") << 0x7c01U << myNaN(); + QTest::newRow("nan2") << raw("\xfc\x01") << 0xfc01U << myNaN(); + QTest::newRow("nan3") << raw("\x7e\x00") << 0x7e00U << myNaN(); + QTest::newRow("nan4") << raw("\xfe\x00") << 0xfe00U << myNaN(); +} + void addColumns() { QTest::addColumn<QByteArray>("output"); diff --git a/src/3rdparty/tinycbor/tests/encoder/tst_encoder.cpp b/src/3rdparty/tinycbor/tests/encoder/tst_encoder.cpp index f30c522601..458f55eb10 100644 --- a/src/3rdparty/tinycbor/tests/encoder/tst_encoder.cpp +++ b/src/3rdparty/tinycbor/tests/encoder/tst_encoder.cpp @@ -41,6 +41,13 @@ class tst_Encoder : public QObject { Q_OBJECT private slots: + void floatAsHalfFloat_data(); + void floatAsHalfFloat(); + void halfFloat_data(); + void halfFloat(); + void floatAsHalfFloatCloseToZero_data(); + void floatAsHalfFloatCloseToZero(); + void floatAsHalfFloatNaN(); void fixed_data(); void fixed(); void strings_data(); @@ -178,21 +185,127 @@ CborError encodeVariant(CborEncoder *encoder, const QVariant &v) return CborErrorUnknownType; } -void compare(const QVariant &input, const QByteArray &output) +template <typename Input, typename FnUnderTest> +void encodeOne(Input input, FnUnderTest fn_under_test, QByteArray &buffer, CborError &error) { - QByteArray buffer(output.length(), Qt::Uninitialized); uint8_t *bufptr = reinterpret_cast<quint8 *>(buffer.data()); CborEncoder encoder; cbor_encoder_init(&encoder, bufptr, buffer.length(), 0); - QCOMPARE(encodeVariant(&encoder, input), CborNoError); - QCOMPARE(encoder.remaining, size_t(1)); - QCOMPARE(cbor_encoder_get_extra_bytes_needed(&encoder), size_t(0)); + error = fn_under_test(&encoder, input); + + if (error == CborNoError) { + QCOMPARE(encoder.remaining, size_t(1)); + QCOMPARE(cbor_encoder_get_extra_bytes_needed(&encoder), size_t(0)); + + buffer.resize(int(cbor_encoder_get_buffer_size(&encoder, bufptr))); + } +} - buffer.resize(int(cbor_encoder_get_buffer_size(&encoder, bufptr))); +template <typename Input, typename FnUnderTest> +void compare(Input input, FnUnderTest fn_under_test, const QByteArray &output) +{ + QByteArray buffer(output.length(), Qt::Uninitialized); + CborError error; + + encodeOne(input, fn_under_test, buffer, error); + if (QTest::currentTestFailed()) + return; + + QCOMPARE(error, CborNoError); QCOMPARE(buffer, output); } +void compare(const QVariant &input, const QByteArray &output) +{ + compare(input, encodeVariant, output); +} + +void tst_Encoder::floatAsHalfFloat_data() +{ + addHalfFloat(); +} + +void tst_Encoder::floatAsHalfFloat() +{ + QFETCH(unsigned, rawInput); + QFETCH(double, floatInput); + QFETCH(QByteArray, output); + + if (rawInput == 0U || rawInput == 0x8000U) + QSKIP("zero values are out of scope of this test case", QTest::SkipSingle); + + if (qIsNaN(floatInput)) + QSKIP("NaN values are out of scope of this test case", QTest::SkipSingle); + + output.prepend('\xf9'); + + compare((float)floatInput, cbor_encode_float_as_half_float, output); +} + +void tst_Encoder::halfFloat_data() +{ + addHalfFloat(); +} + +void tst_Encoder::halfFloat() +{ + QFETCH(unsigned, rawInput); + QFETCH(QByteArray, output); + + uint16_t v = (uint16_t)rawInput; + output.prepend('\xf9'); + + compare(&v, cbor_encode_half_float, output); +} + +void tst_Encoder::floatAsHalfFloatCloseToZero_data() +{ + QTest::addColumn<double>("floatInput"); + + QTest::newRow("+0") << 0.0; + QTest::newRow("-0") << -0.0; + + QTest::newRow("below min.denorm") << ldexp(1.0, -14) * ldexp(1.0, -11); + QTest::newRow("above -min.denorm") << ldexp(-1.0, -14) * ldexp(1.0, -11); +} + +void tst_Encoder::floatAsHalfFloatCloseToZero() +{ + QFETCH(double, floatInput); + + QByteArray buffer(4, Qt::Uninitialized); + CborError error; + + encodeOne((float)floatInput, cbor_encode_float_as_half_float, buffer, error); + + QCOMPARE(error, CborNoError); + + QVERIFY2( + buffer == raw("\xf9\x00\x00") || buffer == raw("\xf9\x80\x00"), + "Got value " + QByteArray::number(floatInput) + " encoded to: " + buffer); +} + +void tst_Encoder::floatAsHalfFloatNaN() +{ + QByteArray buffer(4, Qt::Uninitialized); + CborError error; + + encodeOne(myNaNf(), cbor_encode_float_as_half_float, buffer, error); + + QCOMPARE(error, CborNoError); + QCOMPARE(buffer.size(), 3); + + uint8_t ini_byte = (uint8_t)buffer[0], + exp = (uint8_t)buffer[1] & 0x7cU, + manth = (uint8_t)buffer[1] & 0x03U, + mantl = (uint8_t)buffer[2]; + + QCOMPARE((unsigned)ini_byte, 0xf9U); + QCOMPARE((unsigned)exp, 0x7cU); + QVERIFY((manth | mantl) != 0); +} + void tst_Encoder::fixed_data() { addColumns(); diff --git a/src/3rdparty/tinycbor/tests/parser/tst_parser.cpp b/src/3rdparty/tinycbor/tests/parser/tst_parser.cpp index 74c480bc51..2b10004faa 100644 --- a/src/3rdparty/tinycbor/tests/parser/tst_parser.cpp +++ b/src/3rdparty/tinycbor/tests/parser/tst_parser.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2017 Intel Corporation +** Copyright (C) 2019 Intel Corporation ** ** Permission is hereby granted, free of charge, to any person obtaining a copy ** of this software and associated documentation files (the "Software"), to deal @@ -23,11 +23,22 @@ ****************************************************************************/ #define _XOPEN_SOURCE 700 +#define _DARWIN_C_SOURCE 1 /* need MAP_ANON */ #include <QtTest> #include "cbor.h" #include <stdio.h> #include <stdarg.h> +#if defined(Q_OS_UNIX) +# include <sys/mman.h> +# include <unistd.h> +#elif defined(Q_OS_WIN) +# define WIN32_LEAN_AND_MEAN 1 +# define NOMINMAX 1 +# include <windows.h> +#endif + + namespace QTest { template<> char *toString<CborError>(const CborError &err) { @@ -44,6 +55,8 @@ private slots: // parsing API void integers_data(); void integers(); + void halfFloat_data(); + void halfFloat(); void fixed_data(); void fixed(); void strings_data(); @@ -105,6 +118,100 @@ private slots: void recursionLimit(); }; +struct ParserWrapper +{ + void *realdata = nullptr; + uint8_t *data; + size_t len; + CborParser parser; + CborValue first; + + ~ParserWrapper() { freeMemory(); } + + CborError init(const QByteArray &ba, uint32_t flags = 0) + { + return init(ba.constData(), ba.size(), flags); + } + CborError init(const char *ptr, int n, uint32_t flags = 0) + { + freeMemory(); + data = allocateMemory(n); + memcpy(data, ptr, len); + return cbor_parser_init(data, len, flags, &parser, &first); + } + uint8_t *begin() { return data; } + uint8_t *end() { return data + len; } + + uint8_t *allocateMemory(size_t); + void freeMemory(); + + static const size_t PageSize = 4096; + static inline size_t mmapAllocation(size_t n) + { + // round up and add one page + return (n + 2*PageSize) & ~(PageSize - 1); + } + static bool shouldUseMmap(); +}; + +bool ParserWrapper::shouldUseMmap() +{ + static int v = qEnvironmentVariableIntValue("PARSER_NO_MMAP"); + return !v; +} + +uint8_t *ParserWrapper::allocateMemory(size_t n) +{ + len = n; + if (shouldUseMmap()) { + size_t alloc = mmapAllocation(n); +#if defined(Q_OS_UNIX) + realdata = mmap(nullptr, alloc, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); + Q_ASSERT_X(realdata != MAP_FAILED, "allocateMemory", "mmap failed!"); + + // mark last page inaccessible + uint8_t *ptr = static_cast<uint8_t *>(realdata); + ptr += alloc - PageSize; + mprotect(ptr, PageSize, PROT_NONE); + + ptr -= n; + return ptr; +#elif defined(Q_OS_WIN) + DWORD flAllocationType = MEM_COMMIT | MEM_RESERVE; + DWORD flProtect = PAGE_READWRITE; + realdata = VirtualAlloc(nullptr, alloc, flAllocationType, flProtect); + Q_ASSERT_X(realdata, "allocateMemory", "VirtualAlloc failed!"); + + // mark last page inaccessible + uint8_t *ptr = static_cast<uint8_t *>(realdata); + ptr += alloc - PageSize; + VirtualProtect(ptr, PageSize, PAGE_NOACCESS, nullptr); + + ptr -= n; + return ptr; +#endif + } + realdata = malloc(n); + return static_cast<uint8_t *>(realdata); +} + +void ParserWrapper::freeMemory() +{ + if (shouldUseMmap()) { + if (realdata) { +#if defined(Q_OS_UNIX) + size_t alloc = mmapAllocation(len); + munmap(realdata, alloc); +#elif defined(Q_OS_WIN) + VirtualFree(realdata, 0, MEM_RELEASE); +#endif + } + return; + } + + free(realdata); +} + static CborError qstring_printf(void *out, const char *fmt, ...) { auto str = static_cast<QString *>(out); @@ -166,47 +273,46 @@ bool compareFailed = true; void compareOne_real(const QByteArray &data, const QString &expected, int line, int n = -1) { compareFailed = true; - CborParser parser; - CborValue first; - CborError err = cbor_parser_init(reinterpret_cast<const quint8 *>(data.constData()), data.length(), 0, &parser, &first); + ParserWrapper w; + CborError err = w.init(data); QVERIFY2(!err, QByteArray::number(line) + ": Got error \"" + cbor_error_string(err) + "\""); - if (cbor_value_get_type(&first) == CborArrayType) { + if (cbor_value_get_type(&w.first) == CborArrayType) { size_t len; if (n >= 0) { - QVERIFY(cbor_value_is_length_known(&first)); - QCOMPARE(cbor_value_get_array_length(&first, &len), CborNoError); + QVERIFY(cbor_value_is_length_known(&w.first)); + QCOMPARE(cbor_value_get_array_length(&w.first, &len), CborNoError); QCOMPARE(len, size_t(len)); } else { - QVERIFY(!cbor_value_is_length_known(&first)); - QCOMPARE(cbor_value_get_array_length(&first, &len), CborErrorUnknownLength); + QVERIFY(!cbor_value_is_length_known(&w.first)); + QCOMPARE(cbor_value_get_array_length(&w.first, &len), CborErrorUnknownLength); } - } else if (cbor_value_get_type(&first) == CborMapType) { + } else if (cbor_value_get_type(&w.first) == CborMapType) { size_t len; if (n >= 0) { - QVERIFY(cbor_value_is_length_known(&first)); - QCOMPARE(cbor_value_get_map_length(&first, &len), CborNoError); + QVERIFY(cbor_value_is_length_known(&w.first)); + QCOMPARE(cbor_value_get_map_length(&w.first, &len), CborNoError); QCOMPARE(len, size_t(len)); } else { - QVERIFY(!cbor_value_is_length_known(&first)); - QCOMPARE(cbor_value_get_map_length(&first, &len), CborErrorUnknownLength); + QVERIFY(!cbor_value_is_length_known(&w.first)); + QCOMPARE(cbor_value_get_map_length(&w.first, &len), CborErrorUnknownLength); } - } else if (cbor_value_is_text_string(&first) || cbor_value_is_byte_string(&first)) { + } else if (cbor_value_is_text_string(&w.first) || cbor_value_is_byte_string(&w.first)) { size_t len; - QCOMPARE(cbor_value_calculate_string_length(&first, &len), CborNoError); - if (cbor_value_is_length_known(&first)) { + QCOMPARE(cbor_value_calculate_string_length(&w.first, &len), CborNoError); + if (cbor_value_is_length_known(&w.first)) { size_t len2; - QCOMPARE(cbor_value_get_string_length(&first, &len2), CborNoError); + QCOMPARE(cbor_value_get_string_length(&w.first, &len2), CborNoError); QCOMPARE(len2, len); } else { - QCOMPARE(cbor_value_get_string_length(&first, &len), CborErrorUnknownLength); + QCOMPARE(cbor_value_get_string_length(&w.first, &len), CborErrorUnknownLength); } } - CborError err2 = cbor_value_validate_basic(&first); + CborError err2 = cbor_value_validate_basic(&w.first); QString decoded; - err = parseOne(&first, &decoded); + err = parseOne(&w.first, &decoded); QVERIFY2(!err, QByteArray::number(line) + ": Got error \"" + cbor_error_string(err) + "\"; decoded stream:\n" + decoded.toLatin1()); QCOMPARE(decoded, expected); @@ -215,7 +321,7 @@ void compareOne_real(const QByteArray &data, const QString &expected, int line, QCOMPARE(err2, err); // check that we consumed everything - QCOMPARE((void*)cbor_value_get_next_byte(&first), (void*)data.constEnd()); + QCOMPARE((void*)cbor_value_get_next_byte(&w.first), (void*)w.end()); compareFailed = false; } @@ -237,39 +343,112 @@ void tst_Parser::integers() QFETCH(qint64, expectedValue); QFETCH(bool, inInt64Range); - CborParser parser; - CborValue first; - CborError err = cbor_parser_init(reinterpret_cast<const quint8 *>(data.constData()), data.length(), 0, &parser, &first); + ParserWrapper w; + CborError err = w.init(data); QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\""); - QVERIFY(cbor_value_is_integer(&first)); + QVERIFY(cbor_value_is_integer(&w.first)); uint64_t raw; - cbor_value_get_raw_integer(&first, &raw); + cbor_value_get_raw_integer(&w.first, &raw); QCOMPARE(quint64(raw), expectedRaw); if (isNegative) { - QVERIFY(cbor_value_is_negative_integer(&first)); - QVERIFY(!cbor_value_is_unsigned_integer(&first)); + QVERIFY(cbor_value_is_negative_integer(&w.first)); + QVERIFY(!cbor_value_is_unsigned_integer(&w.first)); } else { - QVERIFY(!cbor_value_is_negative_integer(&first)); - QVERIFY(cbor_value_is_unsigned_integer(&first)); + QVERIFY(!cbor_value_is_negative_integer(&w.first)); + QVERIFY(cbor_value_is_unsigned_integer(&w.first)); } int64_t value; if (inInt64Range) { - cbor_value_get_int64(&first, &value); + cbor_value_get_int64(&w.first, &value); QCOMPARE(qint64(value), expectedValue); } - err = cbor_value_get_int64_checked(&first, &value); + err = cbor_value_get_int64_checked(&w.first, &value); QCOMPARE(err, inInt64Range ? CborNoError : CborErrorDataTooLarge); int ivalue; bool inIntRange = inInt64Range && (expectedValue == int(expectedValue)); - err = cbor_value_get_int_checked(&first, &ivalue); + err = cbor_value_get_int_checked(&w.first, &ivalue); QCOMPARE(err, inIntRange ? CborNoError : CborErrorDataTooLarge); } +static void addHalfFloat() +{ + QTest::addColumn<QByteArray>("data"); + QTest::addColumn<unsigned>("expectedRaw"); + QTest::addColumn<double>("expectedValue"); + + QTest::newRow("+0") << raw("\x00\x00") << 0U << 0.0; + QTest::newRow("-0") << raw("\x80\x00") << 0x8000U << 0.0; + + QTest::newRow("min.denorm") << raw("\x00\x01") << 1U << ldexp(1.0, -14) * ldexp(1.0, -10); + QTest::newRow("-min.denorm") << raw("\x80\x01") << 0x8001U << ldexp(-1.0, -14) * ldexp(1.0, -10); + + QTest::newRow("max.denorm") << raw("\x03\xff") << 0x03ffU << ldexp(1.0, -14) * (1.0 - ldexp(1.0, -10)); + QTest::newRow("-max.denorm") << raw("\x83\xff") << 0x83ffU << ldexp(-1.0, -14) * (1.0 - ldexp(1.0, -10)); + + QTest::newRow("min.norm") << raw("\x04\x00") << 0x0400U << ldexp(1.0, -14); + QTest::newRow("-min.norm") << raw("\x84\x00") << 0x8400U << ldexp(-1.0, -14); + + QTest::newRow("1.0") << raw("\x3c\x00") << 0x3c00U << 1.0; + QTest::newRow("-1.0") << raw("\xbc\x00") << 0xbc00U << -1.0; + + QTest::newRow("1.5") << raw("\x3e\x00") << 0x3e00U << 1.5; + QTest::newRow("-1.5") << raw("\xbe\x00") << 0xbe00U << -1.5; + + QTest::newRow("max") << raw("\x7b\xff") << 0x7bffU << ldexp(1.0, 15) * (2.0 - ldexp(1.0, -10)); + QTest::newRow("-max") << raw("\xfb\xff") << 0xfbffU << ldexp(-1.0, 15) * (2.0 - ldexp(1.0, -10)); + + QTest::newRow("inf") << raw("\x7c\x00") << 0x7c00U << double(INFINITY); + QTest::newRow("-inf") << raw("\xfc\x00") << 0xfc00U << double(-INFINITY); + + QTest::newRow("nan") << raw("\x7c\x01") << 0x7c01U << double(NAN); + QTest::newRow("nan2") << raw("\xfc\x01") << 0xfc01U << double(NAN); + QTest::newRow("nan3") << raw("\x7e\x00") << 0x7e00U << double(NAN); + QTest::newRow("nan4") << raw("\xfe\x00") << 0xfe00U << double(NAN); +} + +void tst_Parser::halfFloat_data() +{ + addHalfFloat(); +} + +void tst_Parser::halfFloat() +{ + QFETCH(QByteArray, data); + QFETCH(unsigned, expectedRaw); + QFETCH(double, expectedValue); + + CborParser parser; + CborValue first; + + data.prepend('\xf9'); + + CborError err = cbor_parser_init(reinterpret_cast<const quint8 *>(data.constData()), data.length(), 0, &parser, &first); + QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\""); + QVERIFY(cbor_value_is_half_float(&first)); + + uint16_t raw; + cbor_value_get_half_float(&first, &raw); + QCOMPARE(raw, uint16_t(expectedRaw)); + + float value; + cbor_value_get_half_float_as_float(&first, &value); + + const double epsilon = ldexp(1.0, -25); + + if (qIsNaN(expectedValue)) { + QVERIFY(qIsNaN(value)); + } else if (qIsInf(expectedValue)) { + QVERIFY(value == (float)expectedValue); + } else { + QVERIFY(qAbs(value - (float)expectedValue) < epsilon); + } +} + void tst_Parser::fixed_data() { addColumns(); @@ -678,14 +857,13 @@ void tst_Parser::chunkedString_data() static void chunkedStringTest(const QByteArray &data, const QString &concatenated, QStringList &chunks, CborType ourType) { - CborParser parser; - CborValue first; - CborError err = cbor_parser_init(reinterpret_cast<const quint8 *>(data.constData()), data.length(), 0, &parser, &first); + ParserWrapper w; + CborError err = w.init(data); QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\""); CborValue value; - QVERIFY(cbor_value_is_array(&first)); - err = cbor_value_enter_container(&first, &value); + QVERIFY(cbor_value_is_array(&w.first)); + err = cbor_value_enter_container(&w.first, &value); QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\""); QVERIFY(cbor_value_is_byte_string(&value) || cbor_value_is_text_string(&value)); @@ -748,9 +926,9 @@ static void chunkedStringTest(const QByteArray &data, const QString &concatenate // confirm EOF QVERIFY(cbor_value_at_end(&value)); - err = cbor_value_leave_container(&first, &value); + err = cbor_value_leave_container(&w.first, &value); QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\""); - QCOMPARE((void*)cbor_value_get_next_byte(&first), (void*)data.constEnd()); + QCOMPARE((void*)cbor_value_get_next_byte(&w.first), (void*)w.end()); } void tst_Parser::chunkedString() @@ -840,18 +1018,17 @@ void tst_Parser::stringLength() QFETCH(QByteArray, data); QFETCH(int, expected); - CborParser parser; - CborValue value; - CborError err = cbor_parser_init(reinterpret_cast<const quint8 *>(data.constData()), data.length(), 0, &parser, &value); + ParserWrapper w; + CborError err = w.init(data); QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\""); size_t result; - err = cbor_value_calculate_string_length(&value, &result); + err = cbor_value_calculate_string_length(&w.first, &result); QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\""); QCOMPARE(result, size_t(expected)); - if (cbor_value_is_length_known(&value)) { - QCOMPARE(cbor_value_get_string_length(&value, &result), CborNoError); + if (cbor_value_is_length_known(&w.first)) { + QCOMPARE(cbor_value_get_string_length(&w.first, &result), CborNoError); QCOMPARE(result, size_t(expected)); } @@ -935,25 +1112,24 @@ void compareOneString(const QByteArray &data, const QString &string, bool expect { compareFailed = true; - CborParser parser; - CborValue value; - CborError err = cbor_parser_init(reinterpret_cast<const quint8 *>(data.constData()), data.length(), 0, &parser, &value); + ParserWrapper w; + CborError err = w.init(data); QVERIFY2(!err, QByteArray::number(line) + ": Got error \"" + cbor_error_string(err) + "\""); bool result; QByteArray bastring = string.toUtf8(); - err = cbor_value_text_string_equals(&value, bastring.constData(), &result); + err = cbor_value_text_string_equals(&w.first, bastring.constData(), &result); QVERIFY2(!err, QByteArray::number(line) + ": Got error \"" + cbor_error_string(err) + "\""); QCOMPARE(result, expected); if (expected) { size_t len; - cbor_value_skip_tag(&value); - if (cbor_value_is_length_known(&value)) { - QCOMPARE(cbor_value_get_string_length(&value, &len), CborNoError); + cbor_value_skip_tag(&w.first); + if (cbor_value_is_length_known(&w.first)) { + QCOMPARE(cbor_value_get_string_length(&w.first, &len), CborNoError); QCOMPARE(int(len), bastring.size()); } - QCOMPARE(cbor_value_calculate_string_length(&value, &len), CborNoError); + QCOMPARE(cbor_value_calculate_string_length(&w.first, &len), CborNoError); QCOMPARE(int(len), bastring.size()); } @@ -1042,13 +1218,12 @@ void tst_Parser::mapFind() QFETCH(QByteArray, data); QFETCH(bool, expected); - CborParser parser; - CborValue value; - CborError err = cbor_parser_init(reinterpret_cast<const quint8 *>(data.constData()), data.length(), 0, &parser, &value); + ParserWrapper w; + CborError err = w.init(data); QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\""); CborValue element; - err = cbor_value_map_find_value(&value, "needle", &element); + err = cbor_value_map_find_value(&w.first, "needle", &element); QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\""); if (expected) { @@ -1119,13 +1294,12 @@ void tst_Parser::checkedIntegers() QFETCH(QVariant, result); int64_t expected = result.toLongLong(); - CborParser parser; - CborValue value; - CborError err = cbor_parser_init(reinterpret_cast<const quint8 *>(data.constData()), data.length(), 0, &parser, &value); + ParserWrapper w; + CborError err = w.init(data); QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\""); int64_t v; - err = cbor_value_get_int64_checked(&value, &v); + err = cbor_value_get_int64_checked(&w.first, &v); if (result.isNull()) { QCOMPARE(err, CborErrorDataTooLarge); } else { @@ -1133,7 +1307,7 @@ void tst_Parser::checkedIntegers() } int v2; - err = cbor_value_get_int_checked(&value, &v2); + err = cbor_value_get_int_checked(&w.first, &v2); if (result.isNull() || expected < std::numeric_limits<int>::min() || expected > std::numeric_limits<int>::max()) { QCOMPARE(err, CborErrorDataTooLarge); } else { @@ -1154,14 +1328,13 @@ void tst_Parser::validation() QFETCH(CborError, expectedError); QString decoded; - CborParser parser; - CborValue first; - CborError err = cbor_parser_init(reinterpret_cast<const quint8 *>(data.constData()), data.length(), flags, &parser, &first); + ParserWrapper w; + CborError err = w.init(data, uint32_t(flags)); QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\""); - CborError err2 = cbor_value_validate_basic(&first); - CborError err3 = cbor_value_validate(&first, CborValidateBasic); - err = parseOne(&first, &decoded); + CborError err2 = cbor_value_validate_basic(&w.first); + CborError err3 = cbor_value_validate(&w.first, CborValidateBasic); + err = parseOne(&w.first, &decoded); QCOMPARE(err, expectedError); if (!QByteArray(QTest::currentDataTag()).contains("utf8")) { QCOMPARE(err2, expectedError); @@ -1352,24 +1525,36 @@ void tst_Parser::strictValidation_data() QTest::newRow("overlong-_stringx2-0*8") << raw("\x7f\x60\x7b\0\0\0\0\0\0\0\0\xff") << int(CborValidateShortestNumbers) << CborErrorOverlongEncoding; // strict mode - QTest::newRow("invalid-utf8-1char") << raw("\x61\x80") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString; - QTest::newRow("invalid-utf8-2chars-1") << raw("\x62\xc2\xc0") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString; - QTest::newRow("invalid-utf8-2chars-2") << raw("\x62\xc3\xdf") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString; - QTest::newRow("invalid-utf8-2chars-3") << raw("\x62\xc7\xf0") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString; - QTest::newRow("invalid-utf8-3chars-1") << raw("\x63\xe0\xa0\xc0") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString; - QTest::newRow("invalid-utf8-3chars-2") << raw("\x63\xe0\xc0\xa0") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString; - QTest::newRow("invalid-utf8-4chars-1") << raw("\x64\xf0\x90\x80\xc0") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString; - QTest::newRow("invalid-utf8-4chars-2") << raw("\x64\xf0\x90\xc0\x80") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString; - QTest::newRow("invalid-utf8-4chars-3") << raw("\x64\xf0\xc0\x80\x80") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString; + // UTF-8 sequences with invalid continuation bytes + QTest::newRow("invalid-utf8-bad-continuation-1char") << raw("\x61\x80") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString; + QTest::newRow("invalid-utf8-bad-continuation-2chars-1") << raw("\x62\xc2\xc0") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString; + QTest::newRow("invalid-utf8-bad-continuation-2chars-2") << raw("\x62\xc3\xdf") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString; + QTest::newRow("invalid-utf8-bad-continuation-2chars-3") << raw("\x62\xc7\xf0") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString; + QTest::newRow("invalid-utf8-bad-continuation-3chars-1") << raw("\x63\xe0\xa0\xc0") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString; + QTest::newRow("invalid-utf8-bad-continuation-3chars-2") << raw("\x63\xe0\xc0\xa0") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString; + QTest::newRow("invalid-utf8-bad-continuation-4chars-1") << raw("\x64\xf0\x90\x80\xc0") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString; + QTest::newRow("invalid-utf8-bad-continuation-4chars-2") << raw("\x64\xf0\x90\xc0\x80") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString; + QTest::newRow("invalid-utf8-bad-continuation-4chars-3") << raw("\x64\xf0\xc0\x80\x80") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString; + // Too short UTF-8 sequences (in an array so there's a byte after that would make it valid UTF-8 if it were part of the string) + QTest::newRow("invalid-utf8-too-short-2chars") << raw("\x82\x61\xc2\x80") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString; + QTest::newRow("invalid-utf8-too-short-3chars-1") << raw("\x82\x61\xe0\x80") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString; + QTest::newRow("invalid-utf8-too-short-3chars-2") << raw("\x82\x62\xe0\xa0\x80") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString; + QTest::newRow("invalid-utf8-too-short-4chars-1") << raw("\x82\x61\xf0\x80") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString; + QTest::newRow("invalid-utf8-too-short-4chars-2") << raw("\x82\x62\xf0\x90\x80") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString; + QTest::newRow("invalid-utf8-too-short-4chars-3") << raw("\x82\x63\xf0\x90\x80\x80") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString; + // UTF-16 surrogages encoded in UTF-8 QTest::newRow("invalid-utf8-hi-surrogate") << raw("\x63\xed\xa0\x80") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString; QTest::newRow("invalid-utf8-lo-surrogate") << raw("\x63\xed\xb0\x80") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString; QTest::newRow("invalid-utf8-surrogate-pair") << raw("\x66\xed\xa0\x80\xed\xb0\x80") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString; + // Non-Unicode UTF-8 sequences QTest::newRow("invalid-utf8-non-unicode-1") << raw("\x64\xf4\x90\x80\x80") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString; QTest::newRow("invalid-utf8-non-unicode-2") << raw("\x65\xf8\x88\x80\x80\x80") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString; QTest::newRow("invalid-utf8-non-unicode-3") << raw("\x66\xfc\x84\x80\x80\x80\x80") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString; QTest::newRow("invalid-utf8-non-unicode-4") << raw("\x66\xfd\xbf\xbf\xbf\xbf\xbf") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString; + // invalid bytes in UTF-8 QTest::newRow("invalid-utf8-fe") << raw("\x61\xfe") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString; QTest::newRow("invalid-utf8-ff") << raw("\x61\xff") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString; + // Overlong sequences QTest::newRow("invalid-utf8-overlong-1-2") << raw("\x62\xc1\x81") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString; QTest::newRow("invalid-utf8-overlong-1-3") << raw("\x63\xe0\x81\x81") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString; QTest::newRow("invalid-utf8-overlong-1-4") << raw("\x64\xf0\x80\x81\x81") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString; @@ -1525,12 +1710,11 @@ void tst_Parser::strictValidation() QFETCH(CborError, expectedError); QString decoded; - CborParser parser; - CborValue first; - CborError err = cbor_parser_init(reinterpret_cast<const quint8 *>(data.constData()), data.length(), 0, &parser, &first); + ParserWrapper w; + CborError err = w.init(data); QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\""); - err = cbor_value_validate(&first, flags); + err = cbor_value_validate(&w.first, flags); QCOMPARE(err, expectedError); } @@ -1549,12 +1733,11 @@ void tst_Parser::incompleteData() QFETCH(QString, expected); for (int len = 0; len < data.length() - 1; ++len) { - CborParser parser; - CborValue first; - CborError err = cbor_parser_init(reinterpret_cast<const quint8 *>(data.constData()), len, 0, &parser, &first); + ParserWrapper w; + CborError err = w.init(data.constData(), len); if (!err) { QString decoded; - err = parseOne(&first, &decoded); + err = parseOne(&w.first, &decoded); } if (err != CborErrorUnexpectedEOF) qDebug() << "Length is" << len; @@ -1583,14 +1766,13 @@ void tst_Parser::endPointer() QFETCH(int, offset); QString decoded; - CborParser parser; - CborValue first; - CborError err = cbor_parser_init(reinterpret_cast<const quint8 *>(data.constData()), data.length(), 0, &parser, &first); + ParserWrapper w; + CborError err = w.init(data); QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\""); - err = parseOne(&first, &decoded); + err = parseOne(&w.first, &decoded); QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\""); - QCOMPARE(int(cbor_value_get_next_byte(&first) - reinterpret_cast<const quint8 *>(data.constBegin())), offset); + QCOMPARE(int(cbor_value_get_next_byte(&w.first) - w.begin()), offset); } void tst_Parser::recursionLimit_data() @@ -1638,24 +1820,23 @@ void tst_Parser::recursionLimit() { QFETCH(QByteArray, data); - CborParser parser; - CborValue first; - CborError err = cbor_parser_init(reinterpret_cast<const quint8 *>(data.constData()), data.length(), 0, &parser, &first); + ParserWrapper w; + CborError err = w.init(data); QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\""); // check that it is valid: - CborValue it = first; + CborValue it = w.first; { QString dummy; err = parseOne(&it, &dummy); QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\""); } - it = first; + it = w.first; err = cbor_value_advance(&it); QCOMPARE(err, CborErrorNestingTooDeep); - it = first; + it = w.first; if (cbor_value_is_map(&it)) { CborValue dummy; err = cbor_value_map_find_value(&it, "foo", &dummy); |