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'; ...
.
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 const
s 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.