php_nub_qq
php_nub_qq

Reputation: 16055

Browser read integer from binary string

I have for example here this string

'x���'

Which you may possibly not see depending on the devide you're using. That's the number 2024000250 encoded as a 32 bit signed big endian integer, which I've generated using Node

let buffer = new Buffer(4);
b.writeInt32BE(2024000250).toString();

I'm receiving the 4 bytes in question on the client side but I can't seem to find how to turn them back into an integer...

Upvotes: 1

Views: 535

Answers (2)

php_nub_qq
php_nub_qq

Reputation: 16055

Well I finally got around to getting this to work.

It is not quite what I started off with but I'm just gonna post this for some other lost souls.

It is worth mentioning that ibrahim's answer contains most of the necessary information but is trying to satisfy the XY problem which my question ended up being.

I just send my binary data, as binary

let buffer = new Buffer(4);
buffer.writeInt32BE(2024000250);

// websocket connection
connection.send(buffer);

Then in the browser

// message listener
let reader = new FileReader();
reader.addEventListener('loadend', () => {
  let view = new DataView(reader.result);

  // there goes the precious data
  console.log(view.getInt32());
});
reader.readAsArrayBuffer(message.data);

In all honesty this tickles my gag reflex. Why am I using a file reader to get some data out of a binary message? There is a good chance a better way of doing this exists, if so please add to this answer.

Other methods I found are the fetch API which is no better than the file reader in terms of hack rating and Blob.prototype.arrayBuffer which is not yet supported fully.

Upvotes: 0

ibrahim tanyalcin
ibrahim tanyalcin

Reputation: 6501

I might be dead wrong here. But as far as I remember unicode characters can be between 2-4 bytes. When you transfer your binary data as text to client-side you risk corrupting this information because the client is going to interpret them as unicode.

If I were to convert that text to a blob on client side:

var b = new Blob(['x���'],{type:"application/octet-stream"});
b.size; //10 

As you can see I receive 10 bytes, which is wrong, it should have been 4.

You can transfer the data directly as a binary string, since you are using Node, on the server side:

function createBuffer(v){
    var b = new ArrayBuffer(4),
        vw = new DataView(b);
    vw.setInt32(0,v);
    return b;
}

This will create your buffer, now you cannot just send this as it is to client, either represent it as a json or directly as a binary string. To represent it as binary you don't need the above function, you could have done:

("0".repeat(32) + (2024000250).toString(2)).slice(-32); //"01111000101000111100101011111010"

If you want json, you can do:

function convertBuffToBinaryStr(buff){
    var res = [],
        l = buff.byteLength,
        v = new DataView(buff);
    for (var i = 0; i < l; ++i){
        res.push(v.getUint8(i));
    }
    return JSON.stringify(res);
}

Now try seeing what this outputs:

convertBuffToBinaryStr(createBuffer(2024000250)); //"[120,163,202,250]"

Back on the client-side you have to interpret this:

function interpret(json){
    json = JSON.parse(json);
    return parseInt(json.map((d)=>("0".repeat(8) + d.toString(2)).slice(-8)).join(""),2);
}

Now try:

interpret("[120,163,202,250]"); //2024000250

Note: For your interpret function, you have to use dataView to setUint8 and the use getInt32 at the end, since you are using signed integers, above won't work for all cases.

Upvotes: 1

Related Questions