summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlex Blasche <alexander.blasche@qt.io>2019-02-11 16:28:05 +0100
committerAlex Blasche <alexander.blasche@qt.io>2019-02-15 11:31:29 +0000
commit68982ef782d7e7c23ce25619f8be2bee1bca355d (patch)
treeaed50b0efa6f7f3e61b19dd476536ee7acb3672a
parent1606ccb76ba72990df652fbd7f01d709ae20b63c (diff)
Ensure SDP records can be byte arrays/hex encoded
This addresses the issue on Bluez only. macOS ignore such attribute values and WinRT implicitly converts them to hex strings. The macOS debug stream operator produced slightly different output compared to the other platforms. The output between the platforms must match though. Therefore, the general version was copied over to macOS. Task-number: QTBUG-73328 Change-Id: Ieea2a3a559b5686f7f7d16d5c75dd9ef2782cdf5 Reviewed-by: Oliver Wolff <oliver.wolff@qt.io>
-rw-r--r--src/bluetooth/qbluetoothserviceinfo.cpp9
-rw-r--r--src/bluetooth/qbluetoothserviceinfo_bluez.cpp17
-rw-r--r--src/bluetooth/qbluetoothserviceinfo_osx.mm59
-rw-r--r--src/bluetooth/qbluetoothserviceinfo_winrt.cpp8
-rw-r--r--tests/auto/qbluetoothserviceinfo/tst_qbluetoothserviceinfo.cpp45
5 files changed, 105 insertions, 33 deletions
diff --git a/src/bluetooth/qbluetoothserviceinfo.cpp b/src/bluetooth/qbluetoothserviceinfo.cpp
index 74b17ac4..7c3780ec 100644
--- a/src/bluetooth/qbluetoothserviceinfo.cpp
+++ b/src/bluetooth/qbluetoothserviceinfo.cpp
@@ -413,6 +413,9 @@ void QBluetoothServiceInfo::setDevice(const QBluetoothDeviceInfo &device)
If the service information is already registered with the platform's SDP database,
the database entry will not be updated until \l registerService() was called again.
+ \note If an attribute expectes a byte-encoded value (e.g. Bluetooth HID services),
+ it should be set as QByteArray.
+
\sa isRegistered(), registerService()
*/
void QBluetoothServiceInfo::setAttribute(quint16 attributeId, const QVariant &value)
@@ -578,6 +581,10 @@ static void dumpAttributeVariant(QDebug dbg, const QVariant &var, const QString&
dbg << QString::asprintf("%sstring %s\n", indent.toUtf8().constData(),
var.toString().toUtf8().constData());
break;
+ case QMetaType::QByteArray:
+ dbg << QString::asprintf("%sbytearray %s\n", indent.toUtf8().constData(),
+ var.toByteArray().toHex().constData());
+ break;
case QMetaType::Bool:
dbg << QString::asprintf("%sbool %d\n", indent.toUtf8().constData(), var.toBool());
break;
@@ -631,7 +638,7 @@ QDebug operator<<(QDebug dbg, const QBluetoothServiceInfo &info)
{
QDebugStateSaver saver(dbg);
dbg.noquote() << "\n";
- QList<quint16> attributes = info.attributes();
+ const QList<quint16> attributes = info.attributes();
for (quint16 id : attributes) {
dumpAttributeVariant(dbg, info.attribute(id), QStringLiteral("(%1)\t").arg(id));
}
diff --git a/src/bluetooth/qbluetoothserviceinfo_bluez.cpp b/src/bluetooth/qbluetoothserviceinfo_bluez.cpp
index 09829b13..5f57e19e 100644
--- a/src/bluetooth/qbluetoothserviceinfo_bluez.cpp
+++ b/src/bluetooth/qbluetoothserviceinfo_bluez.cpp
@@ -103,17 +103,16 @@ static void writeAttribute(QXmlStreamWriter *stream, const QVariant &attribute)
QString::number(attribute.value<qint32>(), 16));
//stream->writeAttribute(QStringLiteral("name"), foo);
break;
+ case QMetaType::QByteArray:
+ stream->writeEmptyElement(QStringLiteral("text"));
+ stream->writeAttribute(QStringLiteral("value"),
+ QString::fromLatin1(attribute.value<QByteArray>().toHex().constData()));
+ stream->writeAttribute(QStringLiteral("encoding"), QStringLiteral("hex"));
+ break;
case QMetaType::QString:
stream->writeEmptyElement(QStringLiteral("text"));
- if (/* require hex encoding */ false) {
- stream->writeAttribute(QStringLiteral("value"), QString::fromLatin1(
- attribute.value<QString>().toUtf8().toHex().constData()));
- stream->writeAttribute(QStringLiteral("encoding"), QStringLiteral("hex"));
- } else {
- stream->writeAttribute(QStringLiteral("value"), attribute.value<QString>());
- stream->writeAttribute(QStringLiteral("encoding"), QStringLiteral("normal"));
- }
- //stream->writeAttribute(QStringLiteral("name"), foo);
+ stream->writeAttribute(QStringLiteral("value"), attribute.value<QString>());
+ stream->writeAttribute(QStringLiteral("encoding"), QStringLiteral("normal"));
break;
case QMetaType::Bool:
stream->writeEmptyElement(QStringLiteral("boolean"));
diff --git a/src/bluetooth/qbluetoothserviceinfo_osx.mm b/src/bluetooth/qbluetoothserviceinfo_osx.mm
index 27da70fc..34de4695 100644
--- a/src/bluetooth/qbluetoothserviceinfo_osx.mm
+++ b/src/bluetooth/qbluetoothserviceinfo_osx.mm
@@ -304,80 +304,93 @@ QBluetoothServiceInfo &QBluetoothServiceInfo::operator=(const QBluetoothServiceI
return *this;
}
-static void dumpAttributeVariant(const QVariant &var, const QString indent)
+static void dumpAttributeVariant(QDebug dbg, const QVariant &var, const QString& indent)
{
switch (int(var.type())) {
case QMetaType::Void:
- qDebug("%sEmpty", indent.toLocal8Bit().constData());
+ dbg << QString::asprintf("%sEmpty\n", indent.toUtf8().constData());
break;
case QMetaType::UChar:
- qDebug("%suchar %u", indent.toLocal8Bit().constData(), var.toUInt());
+ dbg << QString::asprintf("%suchar %u\n", indent.toUtf8().constData(), var.toUInt());
break;
case QMetaType::UShort:
- qDebug("%sushort %u", indent.toLocal8Bit().constData(), var.toUInt());
+ dbg << QString::asprintf("%sushort %u\n", indent.toUtf8().constData(), var.toUInt());
+ break;
case QMetaType::UInt:
- qDebug("%suint %u", indent.toLocal8Bit().constData(), var.toUInt());
+ dbg << QString::asprintf("%suint %u\n", indent.toUtf8().constData(), var.toUInt());
break;
case QMetaType::Char:
- qDebug("%schar %d", indent.toLocal8Bit().constData(), var.toInt());
+ dbg << QString::asprintf("%schar %d\n", indent.toUtf8().constData(), var.toInt());
break;
case QMetaType::Short:
- qDebug("%sshort %d", indent.toLocal8Bit().constData(), var.toInt());
+ dbg << QString::asprintf("%sshort %d\n", indent.toUtf8().constData(), var.toInt());
break;
case QMetaType::Int:
- qDebug("%sint %d", indent.toLocal8Bit().constData(), var.toInt());
+ dbg << QString::asprintf("%sint %d\n", indent.toUtf8().constData(), var.toInt());
break;
case QMetaType::QString:
- qDebug("%sstring %s", indent.toLocal8Bit().constData(), var.toString().toLocal8Bit().constData());
+ dbg << QString::asprintf("%sstring %s\n", indent.toUtf8().constData(),
+ var.toString().toUtf8().constData());
+ break;
+ case QMetaType::QByteArray:
+ dbg << QString::asprintf("%sbytearray %s\n", indent.toUtf8().constData(),
+ var.toByteArray().toHex().constData());
break;
case QMetaType::Bool:
- qDebug("%sbool %d", indent.toLocal8Bit().constData(), var.toBool());
+ dbg << QString::asprintf("%sbool %d\n", indent.toUtf8().constData(), var.toBool());
break;
case QMetaType::QUrl:
- qDebug("%surl %s", indent.toLocal8Bit().constData(), var.toUrl().toString().toLocal8Bit().constData());
+ dbg << QString::asprintf("%surl %s\n", indent.toUtf8().constData(),
+ var.toUrl().toString().toUtf8().constData());
break;
case QVariant::UserType:
if (var.userType() == qMetaTypeId<QBluetoothUuid>()) {
QBluetoothUuid uuid = var.value<QBluetoothUuid>();
switch (uuid.minimumSize()) {
case 0:
- qDebug("%suuid NULL", indent.toLocal8Bit().constData());
+ dbg << QString::asprintf("%suuid NULL\n", indent.toUtf8().constData());
break;
case 2:
- qDebug("%suuid %04x", indent.toLocal8Bit().constData(), uuid.toUInt16());
+ dbg << QString::asprintf("%suuid2 %04x\n", indent.toUtf8().constData(),
+ uuid.toUInt16());
break;
case 4:
- qDebug("%suuid %08x", indent.toLocal8Bit().constData(), uuid.toUInt32());
+ dbg << QString::asprintf("%suuid %08x\n", indent.toUtf8().constData(),
+ uuid.toUInt32());
break;
case 16:
- qDebug("%suuid %s", indent.toLocal8Bit().constData(), QByteArray(reinterpret_cast<const char *>(uuid.toUInt128().data), 16).toHex().constData());
+ dbg << QString::asprintf("%suuid %s\n",
+ indent.toUtf8().constData(),
+ QByteArray(reinterpret_cast<const char *>(uuid.toUInt128().data), 16).toHex().constData());
break;
default:
- qDebug("%suuid ???", indent.toLocal8Bit().constData());
- ;
+ dbg << QString::asprintf("%suuid ???\n", indent.toUtf8().constData());
}
} else if (var.userType() == qMetaTypeId<QBluetoothServiceInfo::Sequence>()) {
- qDebug("%sSequence", indent.toLocal8Bit().constData());
+ dbg << QString::asprintf("%sSequence\n", indent.toUtf8().constData());
const QBluetoothServiceInfo::Sequence *sequence = static_cast<const QBluetoothServiceInfo::Sequence *>(var.data());
for (const QVariant &v : *sequence)
- dumpAttributeVariant(v, indent + QLatin1Char('\t'));
+ dumpAttributeVariant(dbg, v, indent + QLatin1Char('\t'));
} else if (var.userType() == qMetaTypeId<QBluetoothServiceInfo::Alternative>()) {
- qDebug("%sAlternative", indent.toLocal8Bit().constData());
+ dbg << QString::asprintf("%sAlternative\n", indent.toUtf8().constData());
const QBluetoothServiceInfo::Alternative *alternative = static_cast<const QBluetoothServiceInfo::Alternative *>(var.data());
for (const QVariant &v : *alternative)
- dumpAttributeVariant(v, indent + QLatin1Char('\t'));
+ dumpAttributeVariant(dbg, v, indent + QLatin1Char('\t'));
}
break;
default:
- qDebug("%sunknown variant type %d", indent.toLocal8Bit().constData(), var.userType());
+ dbg << QString::asprintf("%sunknown variant type %d\n", indent.toUtf8().constData(),
+ var.userType());
}
}
QDebug operator << (QDebug dbg, const QBluetoothServiceInfo &info)
{
+ QDebugStateSaver saver(dbg);
+ dbg.noquote() << "\n";
const QList<quint16> attributes = info.attributes();
for (quint16 id : attributes) {
- dumpAttributeVariant(info.attribute(id), QString::fromLatin1("(%1)\t").arg(id));
+ dumpAttributeVariant(dbg, info.attribute(id), QString::fromLatin1("(%1)\t").arg(id));
}
return dbg;
}
diff --git a/src/bluetooth/qbluetoothserviceinfo_winrt.cpp b/src/bluetooth/qbluetoothserviceinfo_winrt.cpp
index 45262735..e806096f 100644
--- a/src/bluetooth/qbluetoothserviceinfo_winrt.cpp
+++ b/src/bluetooth/qbluetoothserviceinfo_winrt.cpp
@@ -297,6 +297,14 @@ static ComPtr<IBuffer> bufferFromAttribute(const QVariant &attribute)
hr = writer->WriteInt64(attribute.value<qint64>());
Q_ASSERT_SUCCEEDED(hr);
break;
+ case QMetaType::QByteArray: {
+ qCDebug(QT_BT_WINRT) << Q_FUNC_INFO << "Registering attribute of type QMetaType::QByteArray:" << attribute.value<QString>();
+ const QString stringValue = QString::fromLatin1(attribute.value<QByteArray>().toHex());
+ const bool writeSuccess = writeStringHelper(stringValue, writer);
+ if (!writeSuccess)
+ return nullptr;
+ break;
+ }
case QMetaType::QString: {
qCDebug(QT_BT_WINRT) << Q_FUNC_INFO << "Registering attribute of type QMetaType::QString:" << attribute.value<QString>();
const QString stringValue = attribute.value<QString>();
diff --git a/tests/auto/qbluetoothserviceinfo/tst_qbluetoothserviceinfo.cpp b/tests/auto/qbluetoothserviceinfo/tst_qbluetoothserviceinfo.cpp
index ae8cf5d0..10c4bd3b 100644
--- a/tests/auto/qbluetoothserviceinfo/tst_qbluetoothserviceinfo.cpp
+++ b/tests/auto/qbluetoothserviceinfo/tst_qbluetoothserviceinfo.cpp
@@ -61,6 +61,8 @@ private slots:
void tst_assignment();
void tst_serviceClassUuids();
+
+ void tst_writeByteArray();
};
tst_QBluetoothServiceInfo::tst_QBluetoothServiceInfo()
@@ -385,6 +387,49 @@ void tst_QBluetoothServiceInfo::tst_serviceClassUuids()
QCOMPARE(svclids.at(1), QBluetoothUuid(QBluetoothUuid::SerialPort));
}
+static QByteArray debugOutput;
+
+void debugHandler(QtMsgType type, const QMessageLogContext &, const QString &msg)
+{
+ switch (type) {
+ case QtDebugMsg :
+ debugOutput = msg.toLocal8Bit();
+ break;
+ default:
+ break;
+ }
+}
+
+void tst_QBluetoothServiceInfo::tst_writeByteArray()
+{
+ // We cannot directly test the produced XML output for Bluez
+ // as there no public API to retrieve it and it would be Bluez specific.
+ // However we can check the debug output.
+ // It should contain a qbyteArray rather than a string. In the XML the QByteArray
+ // is converted to a text tag with hex encoding.
+
+ const QByteArray expected("\n (518)\tSequence\n (518)\t\tSequence\n (518)\t\t\tuchar 34\n (518)\t\t\tbytearray 05010906a101850105079508750119e029e7150025018102950175088103050795067508150026ff00190029ff8100050895057501190129059102950175039103c005010902a10185020901a1000509190129031500250175019503810275059501810105010930093109381581257f750895038106c0c0\n");
+
+ const QByteArray hidDescriptor =
+ QByteArray::fromHex("05010906a101850105079508750119e029e7150025018102950175088103050795067508150026FF00190029FF8100050895057501190129059102950175039103c005010902a10185020901a1000509190129031500250175019503810275059501810105010930093109381581257f750895038106c0c0");
+ const QBluetoothServiceInfo::Sequence hidDescriptorList({
+ QVariant::fromValue(quint8(0x22)), // Report type
+ QByteArray(hidDescriptor) // Descriptor array
+ });
+ const QBluetoothServiceInfo::Sequence hidDescriptorListSeq({
+ QVariant::fromValue(hidDescriptorList)
+ });
+ QBluetoothServiceInfo srvInfo;
+ srvInfo.setAttribute(0x0206, QVariant::fromValue(hidDescriptorListSeq));
+
+ const QVariant attribute = srvInfo.attribute(0x0206);
+ debugOutput.clear();
+ qInstallMessageHandler(debugHandler);
+ qDebug() << srvInfo;
+ qInstallMessageHandler(nullptr);
+ QCOMPARE(debugOutput, expected);
+}
+
QTEST_MAIN(tst_QBluetoothServiceInfo)
#include "tst_qbluetoothserviceinfo.moc"