Endianness安全复制二进制数据

时间:2016-11-24 13:34:26

标签: javascript endianness arraybuffer typed-arrays

我试图用ArrayBuffer操纵二进制数据。如果原始ArrayBuffer看起来像这样:

var buffer = new ArrayBuffer(40);
var dv = new DataView(buffer);

var num = 0;
for(var i = 0; i < 40; i+=2) {
    dv.setUint16(i, num++);
}

然后ArrayBuffer有20长度的Uint16Array。我想预先添加额外的二进制数据,而不是追加。让我们说我想要像这样预先添加5个字节的Uint8:

ArrayBuffer[0] = 10;
ArrayBuffer[1] = 20;
ArrayBuffer[2] = 30;
ArrayBuffer[3] = 40;
ArrayBuffer[4] = 50;
ArrayBuffer[5 ~ 25] = Original Data

据我所知,ArrayBuffer中没有类似前置的方法,所以我自己做了。这并不重要,但考虑到字数会让我疯狂。

我生成了前5个字节的数据,因此我可以手动设置字节序,但原始数据来自外部,因此数据可能是Little Endian和Big Endian。

我为Node.js和Web浏览器制作了一些二进制数据模块都可以使用,基本用法是使用这个模块从Web浏览器中预先添加额外的二进制数据,然后浏览器将其发送到服务器,然后服务器也从这个模块读取这个二进制数据,并拆分为prepended和orignal。

但问题是,如果浏览器是指使用little-endian的客户端计算机,而使用big-endian的服务器,原始数据可能无法正确读取,因为它们具有不同的字节顺序。

我将原始数据附加到这样的新二进制数据上。新的二进制数据在0~5字节时有不同的5字节数据。所以我必须写入5个字节的偏移量。

// write rest of data
var newBuffer = new ArrayBuffer(5 + origBuffer.byteLength);
var ndv = new DataView(newBuffer);
var dv = new DataView(origBuffer);    

for(var i = 0; i < origBuffer.byteLength; i++) {
    var offset = 5 + i;
    ndv.setUint8(offset, dv.getUint8(i));
}

在本地计算机上进行测试很好,因为服务器和客户端都使用相同的cpu,但在reallife中,如果它们具有不同的字节顺序,则此模块将无法正常工作。

是否存在使用ArrayBuffer&amp; amp;复制二进制数据的字节顺序安全方法数据视图?或者我应该忘记字节序?任何建议都会非常感激。

2 个答案:

答案 0 :(得分:1)

由于您没有使用带有索引访问权限的Uint16Array,而是使用DataView及其setUint16 method,因此字节顺序始终默认为big-endian。

答案 1 :(得分:1)

对于字节,它没有关系,因为它们没有字节序,但是如果你得到的数据比一个字节宽(16/32位等),你必须事先知道字节顺序,因为没有办法检测原始的结束(你可以根据数据做一些猜测,但......)。

在大多数情况下,字节流处于所谓的网络顺序,基本上是大端的,DataView默认为。

但是,我建议在向客户端发送任何数据之前实现测试功能。例如,使用isLittleEndian()函数从客户端调用服务器,该函数触发服务器发回16位值,如0xff00。然后测试接收字节的顺序 - 类似于:

function isLittleEndian(callback) {  // callback as request will be async
  // get 0xff00 from server as 2 byte ArrayBuffer here somehow...
  var test = new Uint8Array(arraybufferFromServer);
  callback({isLittleEndian: !test[0]}); // will be 0x00ff as little-endian
}

然后,结果可以与DataView一起使用,使用little-endian标志用于各种方法。

请注意,这适用于数据流,而不一定适用于服务器的CPU架构/ endianess(小端服务器仍然(并且很可能)以big-endian / network顺序发送数据。)