ArrayBufferView Uncaught Error: INDEX_SIZE_ERR: DOM Exception 1
-
29-05-2021 - |
Question
I send binary data over websocket from python server:
data = struct.pack('!BI', 2, 1)
channel.send(channel.BINARY, data)
Data sending works fine. On client side javascript gets it like this:
onbinarydata: function(data) {
alert(data.byteLength);
>> 5
var array = new Uint8Array(data,0,1);
alert(array[0]);
>> 2
var array2 = new Uint32Array(data,1,5);
>> Uncaught Error: INDEX_SIZE_ERR: DOM Exception 1
alert(array2[0]);
How can this happen? Byte length minus byte offset is 4, and BYTY_ELEMENT_SIZE is also 4. First value is read without problems, but next always raise error, whatever type it is. Even if I only set byte offset like this
var array2 = new Uint32Array(data,1);
there is an error.
Solution
One cannot create int32/uint32 array with offset not divisible by 4. The same for int16/uint16 and 2.
This is the limitation of CPU architecture.
Let those 2 variables would be A:Uint16
and B:Uint8
. You can map them onto bytes with different methods:
BBAA
(put value B into Uint16)0BAA
/B0AA
(skip 1 byte for alignment)AAB
(reorder for alignment).
If you don't want to think about big-/little-endiad, reordering and other stuff... i.e. if you still want to put variables into bytes as BAA
for some reason, then use the following idea:
For each not-aligned variable put into corresponding size buffer and copy it byte-by-byte. If misalign is 2 bytes, then copy may be made by pair of bytes.
var array = new Uint8Array(data,0,1);
alert(array);
var array2 = new Uint8Array(data,1,5);
var abuf2 = new ArrayBuffer(4);
var abuf2_8 = new Uint8Array(abuf2);
// using `subarray` won't help, cause it doesn't create a copy like `slice`
// and the same data will have the same inconsistent memory alignment
for (var i = 0; i < 4; i++) abuf2_8[i] = array2[i];
var abuf2_32 = new Uint32Array(abuf2);
alert(abuf2_32[0]);
BTW There's some ready code for packing/unpacking in js:
which are similar to php pack
My code may be more interesting to you, cause there're 2 classes: to pack into binary string and to pack into arraybuffer.