0

I have to implement a binary protocol that is supposed to go over WebSockets.

In C I'd write test data such as :

const char test_message[16] = { '/', 'f', 'o', 'o', 0, 0, 0, 0, ',', 'i', 0, 0, 123, 0, 0, 0 };

(this is a valid message in the protocol I'm implementing).

How to generate a JavaScript ArrayData containing the same bytes in the easiest way (for the programmer) ?

  • I do not want to look up ASCII codes corresponding to the bytes I want to send.

  • I do not want to index each character one by one, e.g. data[0] = '/'; data[1] = 'f'; ....

Jean-Michaël Celerier
  • 7,412
  • 3
  • 54
  • 75

1 Answers1

1

Assuming you want to end up with a Uint8Array or similar, and assuming the only textual characters you'll use are ASCII, you could do:

const message = toMessage(["/", "f", "o", "o", 0, 0, 0, 0, ",", "i", 0, 0, 123, 0, 0, 0]);
// or even
const message = toMessage(["/foo", 0, 0, 0, 0, ",i", 0, 0, 123, 0, 0, 0]);

For the first one, toMessage might be:

function toMessage(source) {
    const array = new Uint8Array(source.length);
    source.forEach((element, index) => {
        array[index] = typeof element === "string" ? element.charCodeAt(0) : element;
    });
    return array;
}

Live example:

function toMessage(source) {
    const array = new Uint8Array(source.length);
    source.forEach((element, index) => {
        array[index] = typeof element === "string" ? element.charCodeAt(0) : element;
    });
    return array;
}

const message = toMessage(["/", "f", "o", "o", 0, 0, 0, 0, ",", "i", 0, 0, 123, 0, 0, 0]);

console.log(message);

If you want the second one that lets you do runs of simple characters as strings, it's slightly more complicated.

function toMessage(source) {
    let length = 0;
    for (const element of source) {
        length += typeof element === "string" ? element.length : 1;
    }
    const array = new Uint8Array(length);
    let index = 0;
    for (const element of source) {
        if (typeof element === "string") {
            for (const ch of element) {
                array[index++] = ch.charCodeAt(0);
            }
        } else {
            array[index++] = element;
        }
    }
    source.forEach((element, index) => {
    });
    return array;
}

Live Example:

function toMessage(source) {
    let length = 0;
    for (const element of source) {
        length += typeof element === "string" ? element.length : 1;
    }
    const array = new Uint8Array(length);
    let index = 0;
    for (const element of source) {
        if (typeof element === "string") {
            for (const ch of element) {
                array[index++] = ch.charCodeAt(0);
            }
        } else {
            array[index++] = element;
        }
    }
    source.forEach((element, index) => {
    });
    return array;
}

const message = toMessage(["/foo", 0, 0, 0, 0, ",i", 0, 0, 123, 0, 0, 0]);

console.log(message);

Those are both off-the-cuff and can be optimized if necessary, or adapted to produce something other than a Uint8Array, but the give you the idea.


Alternatively, if the text characters you want to use are just in tye 7-bit ASCII printable range, that's only 96 characters. You could easily have consts for them:

const L_a = 65;
const L_b = 66;
// ...
const L_A = 97;
const L_B = 98;
// ...

(The list is easily generated, you don't have to type it out.)

Then you wouldn't need a function at all:

const message = UInt8Array.of([L_SLASH, L_f, L_o, L_o, 0, 0, 0, 0, L_COMMA, L_i, 0, 0, 123, 0, 0, 0]);

There is no literal form for typed arrays, so it does involve a function call.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • Thanks, it's extremely depressing that what is "free" in C as done by the compiler needs an O(n) run-time algorithm in JS with branches but I guess there is no easier way. – Jean-Michaël Celerier May 12 '21 at 09:18
  • @Jean-MichaëlCelerier - Different languages and environments designed originally for different things. It's also surprisingly awkward to do DOM manipulation in C. And depressing to think that what is "free" in JavaScript requires manual handling (`malloc`, `free`, etc.) in C... ;-) – T.J. Crowder May 12 '21 at 09:51