Passing protobuf message from Javascript to C++ WebAssembly module

338 views
Skip to first unread message

Csaba Szigeti

unread,
Feb 17, 2022, 2:25:26 PM2/17/22
to Protocol Buffers
I would like to pass a protobuf message from Javascript to a C++ WebAssembly module.

I do receive, and can successfully parse the simpler protobuf messages on the C++ side, however, protobuf is failing to parse the less-simple protobuf messages.

Here is the code that I am using :
```
goog.module('protobufMessageGenerator'); goog.require('proto.my_proto.MyMessage'); function generateMyMessage() { var msg = new proto.my_proto.MyMessage() var internal = new proto.my_proto.MyMessageInternal() internal.setAccentColor("#CC1D24") internal.setLogo("iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAYHSURBVHgB7ZhrbBRVFMf/s7vdR9ul7ba09CXQoqVFqcHwFhMQEh4GDSF+ggQhIT6CCUaN/YCaRsWo6QfAKAkvJVEILzECBSE8CyG0lfAoBQu0ttvndrfbZZ8zu9czd22FD+Lc4cNK3F8yO5mZvXfO/95zzzl3JEbgMcaAx5ykgESTFJBokgISTVJAovk/C2BgoTB8decRbG6GXmJuDzy1xxDp7oYeTNADlU+D586ja/v3QCiEjBdmwTZ+vFAXUBT0/Lib+rmASGsbitdVwTxqFEQRnwEyvmfrDjg3fYOSTz6GOTcXaRPGqxOimZjfj9aqdQjfakHp+mpElQhSS0ugCyZEjLkOHGSNk6azcGsbU1xu1jBpGou0tfNnmlAUdmfte+za3IUs6vMxz+FadnnqLMZCIaYHoRmQO7vRUf0ZshfNh3l0Mbx1ddyFTFmZ9FTS1Ifn2HG49/+MgjVvwJCWhv5DR2DOdgBmM/SgXQC5SNfmLaBRh2PRAm6w9+RpGK1WSCkal1I0it5t38E0KhcZL84GCwZx72I9DKmp0DoA0CuABYLw0GgZcxxIe7qCGxO8fkPE9RG62wpfw2XYp0zmRoc6nVD6+iBJ+oxX0Swg3N5OL+uHJT8fEr2chSOI9Ll4KGUkRguBphswyBHYSsdCHXG5qxdSNIYozYRQFNAjQBnwUPiIwWhP59dMlhFTjSchUYoqDydunNzv5mfTiAzuMUPtot5B+lGgB80CJIsVjKZaNZxfG6gpHYxCoNzv+cd20YEByJ4BLkKyWPi9mByO92Ey8rM84OWDoaJQQnN+/S29R5sgzQIs+XkwWMyQXf18tFRjDPY0soZRFu35618PuoHS04ur8xejq2aDai5sY0bzQYh09/L/mjKz+HXMH0CMZsF7/CSal6+C2eEYFvdvaM7EppEjYZtQzheuarC5oBC2okL4nZ2QnR3wNzRi8Mw5hNvaaVZkmCjB2WdMQ8bk53Cv8TeyN0YJr5yCQA78l69w4dbCAgqfKUBERseXNQjRmirdWANrWZnmoKQ9jBqNyF2xjPu899RZqBnE+uQ4/qizZiPaqtcjeKcV7n0/IUKi7GS4+3AtAtea+GIHtVPjfvb8eQhcuYbQ7bswUfw3ZWdDouwuDwziqc2bqCQpg0hQEkhkDI6FC5A2Yypce/fzUbOOHcOfpE+bgvK9P6Do/bUwkquF2zsQIffJfmkhLDTKjNZAy5p30LxiFXwUiVS6t27ng6LOoopj8SIY0tMhGo0EijkJEmXLkq8+x83lK+H89AsMnDrN7xtsajJLgbm4CBUH98Bz9AS5UhtCLbdhKS6G//cWPFH1LlIKC7lve44eR+sH62BMS4WPZkNFCQSG3yMEEyQWi7F79Y2svrSCddds4OeW19eweC10/xEn4nSyW6vfVBsO9cAP1649rKFsIvuj6kPWUDSOdW7ZxvQgXo2Sg/qvXod95nTkrV5JkSST54e/R2/oiJOSl4cx1R/ddyv+PNjSgpxXlyCLXIeH5+E+xBDeDzAKeb2796CUXAk2Gy/EDOkPqWXIz1Pych+4FSLjXb8cQcWunXxfAIMEoy0VehCegcEzZ2GhEGkrj29g1NxgKSgQ6qN3x0445s2hivYJGGhdMUqI5ryR0IOwgP5DtRjx/HQ+aipKhGqb8jLN7RktVveJU8h+ZbF6RVlZJgGU5ErGQg9iAsK0B25sROqzlXFj6Foml0qvrITW8OdvvknOxpBaXg7V7cJd3TyhWSiC6UFsQ0N7AcXrHY7dQQqTNnpxSkE+tIY/dfFaqb1kjddFvkv1yJwzm0K0BXoQEqD4vFQHMb4w1b2xa98BZM2dA5HUqXh9GBKr7jHcR39FztIl0ItQFDLZ7ZCozumjKKQWc94LF1Hw9lsiXcCUMQLBpmZ4Dh+B9+x5pD8zAbYKwS8a9yOUNWSFNS97jV0qHscaKyfzhCYK1UnUdgqrLyplTS8vZbTPYI+CpP6ICFbre2/dBdgrJyKFrwW1uVj6V0uMwI2byJg1E8bMDDwKwgL+ayQ/7iaapIBEkxSQaJICEk1SQKL5E+3sNu+yTCFZAAAAAElFTkSuQmCC") msg.setInternal(internal) return msg }
```
Using the google-closure-compiler, I compile this protobuf message generator to pure Javascript. I use this code to pass the message to the C++ WebAssembly module :
```
function sendMessage() { Module.self().setMyMessage(module$contents$protobufMessageGenerator_generateMyMessage().serializeBinary()) } sendMessage()
```
I receive the message on the C++ side using this code :
```
void JavascriptPublicInterface::setMyMessage(const QString &myMessage) { if (_myMessage != myMessage) { _myMessage = myMessage; emit myMessageChanged(); } } void JavascriptPublicInterface::setMyMessageEMS(const std::string &myMessage) { setMyMessage(QString::fromStdString(myMessage)); } //... void startListeningToMyMessage(std::function<void(euf_proto::MyMessage myMessage)> listener) { const auto changedListener = [listener]() { const auto newMyMessageString = JavascriptPublicInterface::self()->myMessage(); my_proto::MyMessage myMessagePb; if (myMessagePb.ParseFromString(newMyMessageString.toStdString())) { qDebug() << "C++ : Successfully parsed new MyMessage: " << newMyMessageString; } else { qDebug() << "C++ : Failed to parse new MyMessage: " << newMyMessageString; } qDebug() << "MyMessage received: " << QString::fromStdString(myMessagePb.DebugString()); listener(myMessagePb); }; if (!QObject::connect(JavascriptPublicInterface::self(), &JavascriptPublicInterface::myMessageChanged, changedListener)) { throw std::runtime_error("Failed to connect to JavascriptPublicInterface myMessageChanged"); } }
```


In the Javascript console I see : "C++ : Failed to parse new MyMessage: ..."

I guess that it can be related to the fact that Javascript is using UTF-16 and C++ is using UTF-8 encoding (because the messages that are UTF-8 only can be successfully parsed), so I tried to fix the sending and receiving like this:

```
//For more info see : https://emscripten.org/docs/api_reference/emscripten.h.html?highlight=stringtoutf8 function convertUtf16ToUtf8(input) { var uint8Arr = input var jsString = String.fromCharCode.apply(null, uint8Arr) var lengthBytes = lengthBytesUTF8(jsString)+1 var stringOnWasmHeap = _malloc(lengthBytes) stringToUTF8(jsString, stringOnWasmHeap, lengthBytes) return stringOnWasmHeap } function sendMessage() { var myMessage = convertUtf16ToUtf8(module$contents$protobufMessageGenerator_generateMyMessage().serializeBinary()) Module.self().setMyMessage(myMessage) _free(myMessage) } sendMessage()
```
And I modified the parsing on the C++ side like this :
```
void JavascriptPublicInterface::setMyMessageEMS(const int pointer) { const char* msg = (char*)pointer; setMyMessage(QString::fromStdString(msg)); }
```

But I still get this error : "C++ : Failed to parse new MyMessage: ..."

How could I fix this?

(I am using protobuf 3.19.1 (same version on both the Javascript and the C++ side).)

Csaba Szigeti

unread,
Feb 17, 2022, 2:28:24 PM2/17/22
to Protocol Buffers
I am really sorry. Posting again with correct formatting this time : 


I would like to pass a protobuf message from Javascript to a C++ WebAssembly module.

I do receive, and can successfully parse the simpler protobuf messages on the C++ side, however, protobuf is failing to parse the less-simple protobuf messages.

Here is the code that I am using :

```javascript

goog.module('protobufMessageGenerator');
goog.require('proto.my_proto.MyMessage');

function generateMyMessage() {
    var msg = new proto.my_proto.MyMessage()
        var internal = new proto.my_proto.MyMessageInternal()
    internal.setAccentColor("#CC1D24")
    internal.setLogo("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")
        msg.setInternal(internal)
    return msg
}
```

Using the google-closure-compiler, I compile this protobuf message generator to pure Javascript.
I use this code to pass the message to the C++ WebAssembly module :

```javascript

function sendMessage() {
        Module.self().setMyMessage(module$contents$protobufMessageGenerator_generateMyMessage().serializeBinary())
}
sendMessage()
```

I receive the message on the C++ side using this code :

```cpp

void JavascriptPublicInterface::setMyMessage(const QString &myMessage)
{
        if (_myMessage != myMessage)
        {
                _myMessage = myMessage;
                emit myMessageChanged();
        }
}

void JavascriptPublicInterface::setMyMessageEMS(const std::string &myMessage)
{
        setMyMessage(QString::fromStdString(myMessage));
}

//...

void startListeningToMyMessage(std::function<void(euf_proto::MyMessage myMessage)> listener)
{
        const auto changedListener = [listener]() {
                const auto newMyMessageString = JavascriptPublicInterface::self()->myMessage();
                my_proto::MyMessage myMessagePb;
                if (myMessagePb.ParseFromString(newMyMessageString.toStdString()))
                {
                        qDebug() << "C++ : Successfully parsed new MyMessage: " << newMyMessageString;
                }
                else
                {
                        qDebug() << "C++ : Failed to parse new MyMessage: " << newMyMessageString;
                }

                qDebug() << "MyMessage received: " << QString::fromStdString(myMessagePb.DebugString());

                listener(myMessagePb);
        };
        if (!QObject::connect(JavascriptPublicInterface::self(), &JavascriptPublicInterface::myMessageChanged, changedListener))
        {
                throw std::runtime_error("Failed to connect to JavascriptPublicInterface myMessageChanged");
        }
}
```

In the Javascript console I see : "C++ : Failed to parse new MyMessage: ..."

I guess that it can be related to the fact that Javascript is using UTF-16 and C++ is using UTF-8 encoding (because the messages that are UTF-8 only can be successfully parsed), so I tried to fix the sending and receiving like this:

```javascript

//For more info see : https://emscripten.org/docs/api_reference/emscripten.h.html?highlight=stringtoutf8
function convertUtf16ToUtf8(input) {
        var uint8Arr = input
        var jsString = String.fromCharCode.apply(null, uint8Arr)
        var lengthBytes = lengthBytesUTF8(jsString)+1
        var stringOnWasmHeap = _malloc(lengthBytes)
        stringToUTF8(jsString, stringOnWasmHeap, lengthBytes)
        return stringOnWasmHeap
}

function sendMessage() {
var myMessage = convertUtf16ToUtf8(module$contents$protobufMessageGenerator_generateMyMessage().serializeBinary())
        Module.self().setMyMessage(myMessage)
        _free(myMessage)
}
sendMessage()
```

And I modified the parsing on the C++ side like this :

```cpp

void JavascriptPublicInterface::setMyMessageEMS(const int pointer)
{
    const char* msg = (char*)pointer;
        setMyMessage(QString::fromStdString(msg));
}
```

But I still get this error : "C++ : Failed to parse new MyMessage: ..."

How could I fix this?

(I am using protobuf 3.19.1 (same version on both the Javascript and the C++ side).)

Adam Cozzette

unread,
Feb 17, 2022, 2:49:38 PM2/17/22
to Csaba Szigeti, Protocol Buffers
If only UTF-8 messages are being parsed successfully, then that sounds like a clue to me that you probably need to base64-encode the serialized message. I have only limited experience with JavaScript, but from what I understand, JavaScript strings can only represent Unicode and not raw binary data. So if you need to store raw binary in a JavaScript string then you probably want to base64-encode it (and then decode it on the other side before parsing the message).

--
You received this message because you are subscribed to the Google Groups "Protocol Buffers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to protobuf+u...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/protobuf/9ce5f69e-b6de-4627-b8e1-71b68da574b3n%40googlegroups.com.

Csaba Szigeti

unread,
Feb 18, 2022, 5:39:13 AM2/18/22
to Protocol Buffers

In case if I modify my code, so it is passing a simple string as logo, then I can successfully parse the protobuf message on the C++ side :

```javascript
...
internal.setLogo("logo")
...
```

So I guess that the issue is with this field. The original string is a base64 encoded image. What should I do with this string to fix the parsing?

Csaba Szigeti

unread,
Feb 18, 2022, 12:36:19 PM2/18/22
to Protocol Buffers

The issue is not fixed yet, but I got much-much closer to fixing it.

Using this code, from the Javascript console, I printed my protobuf message as hex : 
```javascript
function buf2hex(buffer) { // buffer is an ArrayBuffer
  return [...new Uint8Array(buffer)]
      .map(x => x.toString(16).padStart(2, '0'))
      .join('');
}

buf2hex(module$contents$protobufMessageGenerator_generatePubDetailsMessage().serializeBinary())
```

I copy pasted it into a.txt, and converted it : 
```bash
cat a.txt | tr ',' '\n' | xargs printf '\\\\x%02x'

```

and I copy pasted this output as well, and generated a.bin like this : 
```bash
echo -n -e \\x2a\\xd2\\x02\\x1a\\x93\\x01\\x0a\\x0c\\x45\\x6d\\x69\\x74\\x74\\x65\\x72\\x20\\x4e\\x61\\x6d\\x65\\x12\\x0d\\x45\\x6d\\x69\\x74\\x74\\x65\\x72\\x20\\x54\\x69\\x74\\x6c\\x65\\x1a\\x74\\x69\\x56\\x42\\x4f\\x52\\x77\\x30\\x4b\\x47\\x67\\x6f\\x41\\x41\\x41\\x41\\x4e\\x53\\x55\\x68\\x45\\x55\\x67\\x41\\x41\\x41\\x41\\x55\\x41\\x41\\x41\\x41\\x46\\x43\\x41\\x59\\x41\\x41\\x41\\x43\\x4e\\x62\\x79\\x62\\x6c\\x41\\x41\\x41\\x41\\x48\\x45\\x6c\\x45\\x51\\x56\\x51\\x49\\x31\\x32\\x50\\x34\\x2f\\x2f\\x38\\x2f\\x77\\x33\\x38\\x47\\x49\\x41\\x58\\x44\\x49\\x42\\x4b\\x45\\x30\\x44\\x48\\x78\\x67\\x6c\\x6a\\x4e\\x42\\x41\\x41\\x4f\\x39\\x54\\x58\\x4c\\x30\\x59\\x34\\x4f\\x48\\x77\\x41\\x41\\x41\\x41\\x42\\x4a\\x52\\x55\\x35\\x45\\x72\\x6b\\x4a\\x67\\x67\\x67\\x3d\\x3d\\x22\\x0a\\x54\\x68\\x61\\x6e\\x6b\\x20\\x79\\x6f\\x75\\x21\\x3a\\x9a\\x01\\x1a\\x08\\x47\\x72\\x65\\x65\\x74\\x69\\x6e\\x67\\x22\\x06\\x48\\x65\\x61\\x64\\x65\\x72\\x2a\\x04\\x42\\x6f\\x64\\x79\\x32\\x06\\x46\\x6f\\x6f\\x74\\x65\\x72\\x3a\\x0c\\x53\\x69\\x6e\\x67\\x6c\\x65\\x41\\x6e\\x73\\x77\\x65\\x72\\x4a\\x12\\x1a\\x07\\x4f\\x70\\x74\\x69\\x6f\\x6e\\x31\\x22\\x07\\x4f\\x70\\x74\\x69\\x6f\\x6e\\x31\\x4a\\x14\\x08\\x02\\x1a\\x07\\x4f\\x70\\x74\\x69\\x6f\\x6e\\x32\\x22\\x07\\x4f\\x70\\x74\\x69\\x6f\\x6e\\x32\\x4a\\x14\\x08\\x04\\x1a\\x07\\x4f\\x70\\x74\\x69\\x6f\\x6e\\x33\\x22\\x07\\x4f\\x70\\x74\\x69\\x6f\\x6e\\x33\\x4a\\x14\\x08\\x06\\x1a\\x07\\x4f\\x70\\x74\\x69\\x6f\\x6e\\x34\\x22\\x07\\x4f\\x70\\x74\\x69\\x6f\\x6e\\x34\\x4a\\x14\\x08\\x08\\x1a\\x07\\x4f\\x70\\x74\\x69\\x6f\\x6e\\x35\\x22\\x07\\x4f\\x70\\x74\\x69\\x6f\\x6e\\x35\\x4a\\x06\\x75\\x72\\x67\\x65\\x6e\\x74\\x52\\x09\\x6c\\x69\\x67\\x68\\x74\\x6e\\x69\\x6e\\x67\\x32\\x06\\x12\\x04\\x6e\\x6f\\x6e\\x65 > a.bin

```

When I add this file as a resource to my C++ WebAssembly app, and load it, everything works fine : 
```cpp

euf_proto::PubDetails pubDetails;
    QByteArray data;
    {
        QString fileName(":/a.bin");
       
        QFile file(fileName);
        if(!file.open(QIODevice::ReadOnly)) {
            qDebug() << "file not opened";
        }
        else
        {
            qDebug() << "file opened";
            data = file.readAll();
        }
    }

    

    if (pubDetails.ParseFromArray(data.data(), data.size()))
    {
        qDebug() << "C++ : Successfully parsed new pubDetails: " << data;
    }
    else
    {
        qDebug() << "C++ : Failed to parse new pubDetails: " << data;
    }

=>

file opened

qtloader.js:382 C++ : Successfully parsed new pubDetails:  "*\xD2\x02\x1A\x93\x01\n\fEmitter Name\x12\rEmitter Title\x1AtiVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==\"\nThank you!:\x9A\x01\x1A\bGreeting\"\x06Header*\x04""Body2\x06""Footer:\fSingleAnswerJ\x12\x1A\x07Option1\"\x07Option1J\x14\b\x02\x1A\x07Option2\"\x07Option2J\x14\b\x04\x1A\x07Option3\"\x07Option3J\x14\b\x06\x1A\x07Option4\"\x07Option4J\x14\b\b\x1A\x07Option5\"\x07Option5J\x06urgentR\tlightning2\x06\x12\x04none"


So basically this means that the protobuf message gets correctly generated on the Javascript side, and even the wire format output is correct as well.
So the issue is with passing this to C++ somehow.

I tried to encode it as hex on the Javascript side, and decode it on the C++ side, but it didn't help.

Csaba Szigeti

unread,
Feb 19, 2022, 3:36:47 PM2/19/22
to Protocol Buffers
I found the solution.

This stackoverflow post described a really similar issue, and it helped me to fix my parsing as well :
https://stackoverflow.com/questions/68750875/protobuf-serialize-deserialize-c-to-js

Here is my updated code, which works well :
I had to update the Javascript side :
```javascript
function sendMessage() {
    Module.self().setMyMessage(module$contents$protobufMessageGenerator_generateMyMessage().serializeBinary().toString())
}
sendMessage()
```
and the C++ side :
```cpp
namespace
{
QByteArray decryptProtobufMessage(const std::string &str)
{
        QStringList strList = QString::fromStdString(str).split(',');
        QByteArray bytedata;
        foreach (const QString &str, strList)
        {
                bytedata += (str.toUInt());
        }
        return bytedata;
}
} // namespace

void JavascriptPublicInterface::setMyMessage(const QByteArray &myMessage)

{
    if (_myMessage != myMessage)
    {
        _myMessage = myMessage;
        emit myMessageChanged();
    }
}

void JavascriptPublicInterface::setMyMessageEMS(const std::string &myMessage)
{
    setMyMessage(decryptProtobufMessage(myMessage));

}

//...

void startListeningToMyMessage(std::function<void(euf_proto::MyMessage myMessage)> listener)
{
    const auto changedListener = [listener]() {
        const auto newMyMessageByteArray = JavascriptPublicInterface::self()->myMessage();
        my_proto::MyMessage myMessagePb;
        if (myMessagePb.ParseFromArray(newMyMessageByteArray.data(), newMyMessageByteArray.size()))
        {
            qDebug() << "C++ : Successfully parsed new MyMessage: " << newMyMessageByteArray;
        }
        else
        {
            qDebug() << "C++ : Failed to parse new MyMessage: " << newMyMessageByteArray;

        }

        qDebug() << "MyMessage received: " << QString::fromStdString(myMessagePb.DebugString());

        listener(myMessagePb);
    };
    if (!QObject::connect(JavascriptPublicInterface::self(), &JavascriptPublicInterface::myMessageChanged, changedListener))
    {
        throw std::runtime_error("Failed to connect to JavascriptPublicInterface myMessageChanged");
    }
}
```

Reply all
Reply to author
Forward
0 new messages