Showing the changes to interface/src/scripting/OSCScriptingInterface.cpp (1 of 4 files). Show all
Unified · Split
| @@ -17,7 +17,7 @@ · 16 unmodified lines | |||
| 17 | #include "OSCScriptingInterface.h" | 17 | #include "OSCScriptingInterface.h" |
| 18 | 18 | ||
| 19 | 19 | ||
| 20 | Q_LOGGING_CATEGORY(osc, "overte.osc") | 20 | Q_LOGGING_CATEGORY(osc, "osc") |
| 21 | 21 | ||
| 22 | enum OSCTag: char { | 22 | enum OSCTag: char { |
| 23 | Int = 'i', | 23 | Int = 'i', |
| @@ -26,7 +26,7 @@ enum OSCTag: char { · 2 unmodified lines | |||
| 26 | Blob = 'b', | 26 | Blob = 'b', |
| 27 | }; | 27 | }; |
| 28 | 28 | ||
| 29 | static const QRegularExpression invalidCharacters = QRegularExpression("([ #*,/?\\[\\]{}])"); | 29 | static const QRegularExpression invalidCharacters = QRegularExpression("([ #*,?\\[\\]{}])"); |
| 30 | static const QMap<QChar, QVariant::Type> typeNameMap = { | 30 | static const QMap<QChar, QVariant::Type> typeNameMap = { |
| 31 | { OSCTag::Int, QVariant::Int }, | 31 | { OSCTag::Int, QVariant::Int }, |
| 32 | { OSCTag::Float, QVariant::Double }, | 32 | { OSCTag::Float, QVariant::Double }, |
| @@ -35,8 +35,8 @@ static const QMap<QChar, QVariant::Type> typeNameMap = { · 2 unmodified lines | |||
| 35 | }; | 35 | }; |
| 36 | 36 | ||
| 37 | 37 | ||
| 38 | OSCScriptingInterface::OSCScriptingInterface(ScriptManager* parent) : | 38 | OSCScriptingInterface::OSCScriptingInterface(QObject* parent) : |
| 39 | _scriptManager(parent), | 39 | QObject(parent), |
| 40 | _receivePort("osc/receivePort", 9000), | 40 | _receivePort("osc/receivePort", 9000), |
| 41 | _receiveHost("osc/receiveHost", "127.0.0.1"), | 41 | _receiveHost("osc/receiveHost", "127.0.0.1"), |
| 42 | _sendPort("osc/sendPort", 9001), | 42 | _sendPort("osc/sendPort", 9001), |
| @@ -63,7 +63,14 @@ void OSCScriptingInterface::receivePacket() { · 20 unmodified lines | |||
| 63 | void OSCScriptingInterface::sendMessage(const QString& address, const QString &argumentTypes, const QVariantList& arguments) { | 63 | void OSCScriptingInterface::sendMessage(const QString& address, const QString &argumentTypes, const QVariantList& arguments) { |
| 64 | Q_ASSERT(_socket); | 64 | Q_ASSERT(_socket); |
| 65 | 65 | ||
| 66 | auto scriptEngine = _scriptManager->engine(); | 66 | // FIXME: how do you get the script engine??? |
| 67 | struct HackRemoveThis { | ||
| 68 | void raiseException(QString msg) { | ||
| 69 | qCCritical(osc) << msg; | ||
| 70 | } | ||
| 71 | }; | ||
| 72 | |||
| 73 | auto scriptEngine = std::make_unique<HackRemoveThis>(); //_scriptManager->engine(); | ||
| 67 | 74 | ||
| 68 | if (address.length() < 2 || address[0] != '/') { | 75 | if (address.length() < 2 || address[0] != '/') { |
| 69 | scriptEngine->raiseException("address must be at least two characters and start with '/'"); | 76 | scriptEngine->raiseException("address must be at least two characters and start with '/'"); |
| @@ -76,14 +83,19 @@ void OSCScriptingInterface::sendMessage(const QString& address, const QString &a · 6 unmodified lines | |||
| 76 | } | 83 | } |
| 77 | 84 | ||
| 78 | if (argumentTypes.length() != arguments.length()) { | 85 | if (argumentTypes.length() != arguments.length()) { |
| 79 | scriptEngine->raiseException(QString("argumentTypes.length (%1) does not match arguments.length (%2)").arg(argumentTypes.length()).arg(argumentTypes.length())); | 86 | scriptEngine->raiseException(QString("argumentTypes.length (%1) does not match arguments.length (%2)").arg(argumentTypes.length()).arg(arguments.length())); |
| 80 | return; | 87 | return; |
| 81 | } | 88 | } |
| 82 | 89 | ||
| 90 | auto pad4 = [](QByteArray& array) { | ||
| 91 | array.append((4 - array.length() % 4) % 4, 0); | ||
| 92 | }; | ||
| 93 | |||
| 83 | QByteArray bytes = address.toUtf8(); | 94 | QByteArray bytes = address.toUtf8(); |
| 84 | 95 | ||
| 85 | // pad to 4-byte boundary with at least one zero for the address string | 96 | // pad to 4-byte boundary with at least one zero for the address string |
| 86 | bytes.append((bytes.length() + 1) % 4, 0); | 97 | bytes.append('\x00'); |
| 98 | pad4(bytes); | ||
| 87 | 99 | ||
| 88 | // comma at the start of the argument list, even if empty | 100 | // comma at the start of the argument list, even if empty |
| 89 | bytes.append(','); | 101 | bytes.append(','); |
| @@ -99,19 +111,23 @@ void OSCScriptingInterface::sendMessage(const QString& address, const QString &a · 9 unmodified lines | |||
| 99 | } | 111 | } |
| 100 | 112 | ||
| 101 | auto expectedType = typeNameMap[argumentTypes[i]]; | 113 | auto expectedType = typeNameMap[argumentTypes[i]]; |
| 102 | if (expectedType != arg.type()) { | 114 | if ( |
| 115 | expectedType != arg.type() && | ||
| 116 | // JS doesn't have ints, so allow doubles to be interpreted as ints | ||
| 117 | arg.type() != QVariant::Double | ||
| 118 | ) { | ||
| 103 | scriptEngine->raiseException(QString("Specified argument type '%1' does not match value of type '%2'").arg(QVariant::typeToName(expectedType)).arg(arg.typeName())); | 119 | scriptEngine->raiseException(QString("Specified argument type '%1' does not match value of type '%2'").arg(QVariant::typeToName(expectedType)).arg(arg.typeName())); |
| 104 | return; | 120 | return; |
| 105 | } | 121 | } |
| 106 | 122 | ||
| 107 | switch (arg.type()) { | 123 | switch (expectedType) { |
| 108 | case QVariant::Int: { | 124 | case QVariant::Int: { |
| 109 | bytes.append(OSCTag::Int); | 125 | bytes.append(OSCTag::Int); |
| 110 | 126 | ||
| 111 | auto* ptr = bodyBytes.data() + bodyBytes.length(); | 127 | auto* ptr = bodyBytes.data() + bodyBytes.length(); |
| 112 | bodyBytes.append(4, 0); | 128 | bodyBytes.append(4, 0); |
| 113 | 129 | ||
| 114 | qToBigEndian(static_cast<qint32>(arg.toInt()), ptr); | 130 | qToBigEndian(static_cast<qint32>(arg.toDouble()), ptr); |
| 115 | } break; | 131 | } break; |
| 116 | 132 | ||
| 117 | case QVariant::Double: { | 133 | case QVariant::Double: { |
| @@ -121,7 +137,7 @@ void OSCScriptingInterface::sendMessage(const QString& address, const QString &a · 3 unmodified lines | |||
| 121 | bodyBytes.append(4, 0); | 137 | bodyBytes.append(4, 0); |
| 122 | 138 | ||
| 123 | // FIXME: use std::bit_cast instead of this hack once c++20 is in | 139 | // FIXME: use std::bit_cast instead of this hack once c++20 is in |
| 124 | auto tmp = arg.toFloat(); | 140 | auto tmp = static_cast<float>(arg.toDouble()); |
| 125 | qToBigEndian(*reinterpret_cast<quint32*>(&tmp), ptr); | 141 | qToBigEndian(*reinterpret_cast<quint32*>(&tmp), ptr); |
| 126 | } break; | 142 | } break; |
| 127 | 143 | ||
| @@ -136,8 +152,10 @@ void OSCScriptingInterface::sendMessage(const QString& address, const QString &a · 8 unmodified lines | |||
| 136 | } | 152 | } |
| 137 | 153 | ||
| 138 | bodyBytes.append(stringArg.toUtf8()); | 154 | bodyBytes.append(stringArg.toUtf8()); |
| 155 | |||
| 139 | // pad to 4-byte boundary with at least one zero for the string | 156 | // pad to 4-byte boundary with at least one zero for the string |
| 140 | bodyBytes.append((bodyBytes.length() + 1) % 4, 0); | 157 | bodyBytes.append('\x00'); |
| 158 | pad4(bodyBytes); | ||
| 141 | } break; | 159 | } break; |
| 142 | 160 | ||
| 143 | case QVariant::ByteArray: { | 161 | case QVariant::ByteArray: { |
| @@ -153,8 +171,8 @@ void OSCScriptingInterface::sendMessage(const QString& address, const QString &a · 9 unmodified lines | |||
| 153 | // write body | 171 | // write body |
| 154 | bodyBytes.append(bytesArg); | 172 | bodyBytes.append(bytesArg); |
| 155 | 173 | ||
| 156 | // pad to 4-byte boundary with at least one zero for the string | 174 | // pad to 4-byte boundary |
| 157 | bodyBytes.append((bodyBytes.length() + 1) % 4, 0); | 175 | pad4(bodyBytes); |
| 158 | } break; | 176 | } break; |
| 159 | 177 | ||
| 160 | // unreachable | 178 | // unreachable |
| @@ -164,11 +182,14 @@ void OSCScriptingInterface::sendMessage(const QString& address, const QString &a · 3 unmodified lines | |||
| 164 | } | 182 | } |
| 165 | } | 183 | } |
| 166 | 184 | ||
| 167 | // pad to 4-byte boundary with at least one zero for the argument list string | 185 | // pad argument type string to 4-byte boundary with at least one zero |
| 168 | bytes.append((bytes.length() + 1) % 4, 0); | 186 | bytes.append('\x00'); |
| 187 | pad4(bytes); | ||
| 169 | 188 | ||
| 170 | // pack the header + body data together for the datagram | 189 | // pack the header + body data together for the datagram |
| 171 | bytes.append(bodyBytes); | 190 | bytes.append(bodyBytes); |
| 172 | 191 | ||
| 173 | _socket->writeDatagram(bytes, QHostAddress(_sendHost.get()), _sendPort.get()); | 192 | _socket->writeDatagram(bytes, QHostAddress(_sendHost.get()), _sendPort.get()); |
| 193 | |||
| 194 | qCDebug(osc) << QHostAddress(_sendHost.get()) << _sendPort.get() << ":" << bytes.toHex(' '); | ||
| 174 | } | 195 | } |