I have a 'binary string' in JavaScript inside of QML, representing raw bytes that I want to pass to C++ (to send over an established socket).
I was using code like this:
// QML
onSomeSignal: {
var proto = new MyMessage(); // https://github.com/dcodeIO/protobuf.js
var bbuf = proto.encode(); // https://github.com/dcodeIO/bytebuffer.js
var bytes = bbuf.toBinary();
messageBridge.send(bytes);
}
// C++
void MessageBridge::send(const QString& data) {
if(m_tcpSocket->state() == QAbstractSocket::ConnectedState) {
m_tcpSocket->write(encodeVarint32(data.length()).toLocal8Bit());
m_tcpSocket->write(data.toLocal8Bit());
}
}
However, I discovered that translating the JavaScript string to a QString was sometimes changing the bytes (presumably because of encodings).
The following code works, but it's inefficient, converting the byte buffer to a binary string, then a JS array, converting to a QVariantList and then piecemeal populating a QByteArray.
// QML
onSomeSignal: {
var bytes = (new MyMessage()).encode().toBinary();
var bytea = [];
for (var i=bytes.length;i--;) bytea[i] = bytes.charCodeAt(i);
messageBridge.send(bytes);
}
// C++
void MessageBridge::send(const QVariantList& data) {
if(m_tcpSocket->state() == QAbstractSocket::ConnectedState) {
m_tcpSocket->write(encodeVarint32(data.length()).toLocal8Bit());
m_tcpSocket->write(data.toLocal8Bit());
QByteArray bytes(data.length(),'\0');
for (int i=0; i<data.length(); i++) bytes[i] = data[i].toInt();
m_tcpSocket->write(bytes);
}
}
What is an efficient way to pass either a ByteBuffer
or binary string from QML/JavaScript to Qt/C++, in a way that gives me something I can write to a QTcpSocket
?
Qt 5.7 does not understand QByteArray from C++ to QML, so it just wraps it into an opaque QVariant, making it useless in QML, except for passing it back into C++ at a later time.
Qt 5.8+ adds support for QByteArray type. When passed from C++ to QML, either as a return variable or a signal parameter, the QByteArray is converted to an ArrayBuffer. This is useful for protobufs, as the protobuf's javascript API can directly decode an ArrayBuffer type.
and the array buffer will nicely fit into a QByteArray:
Now please tell me how to go the other way from a QByteBuffer in C++ to a useful protobuf.js object in a QML signal :)