J'utilise WebGL pour rendre un fichier de maillage codé binaire. Le fichier binaire est écrit au format big-endian (je peux le vérifier en ouvrant le fichier dans un éditeur hexadécimal ou en visualisant le trafic réseau à l'aide de fiddler). Lorsque j'essaie de lire la réponse binaire à l'aide d'un Float32Array ou Int32Array, le binaire est interprété comme little-endian et mes valeurs sont fausses:
// Interpret first 32bits in buffer as an int
var wrongValue = new Int32Array(binaryArrayBuffer)[0];
Je ne trouve aucune référence à l'endianité par défaut des tableaux typés dans http://www.khronos.org/registry/typedarray/specs/latest/ donc je me demande quel est le problème? Dois-je supposer que toutes les données binaires doivent être en petit-boutien lors de la lecture à l'aide de tableaux typés?
Pour contourner le problème, je peux utiliser un objet DataView (décrit dans le lien précédent) et appeler:
// Interpret first 32bits in buffer as an int
var correctValue = new DataView(binaryArrayBuffer).getInt32(0);
Les fonctions DataView telles que "getInt32" lisent les valeurs big-endian par défaut.
(Remarque: j'ai testé en utilisant Google Chrome 15 et Firefox 8 et ils se comportent tous les deux de la même manière)
Malheureusement, le comportement actuel est que l'endianisme est celui du matériel sous-jacent. Comme presque tous les ordinateurs de bureau sont x86, cela signifie petit-boutien. La plupart des ARM OS utilisent le mode little-endian (les processeurs ARM sont bi-endian et peuvent donc fonctionner dans les deux cas).
La raison pour laquelle cela est quelque peu triste est le fait que cela signifie que presque personne ne testera si son code fonctionne sur du matériel big-endian, ce qui fait mal, et le fait que la plate-forme Web entière a été conçue autour d'un code fonctionnant uniformément sur toutes les implémentations et plates-formes, que cela casse.
Pour info, vous pouvez utiliser la fonction javascript suivante pour déterminer l'endianité de la machine, après quoi vous pouvez passer un fichier correctement formaté au client (vous pouvez stocker deux versions du fichier sur le serveur, big endian et little endian):
function checkEndian() {
var arrayBuffer = new ArrayBuffer(2);
var uint8Array = new Uint8Array(arrayBuffer);
var uint16array = new Uint16Array(arrayBuffer);
uint8Array[0] = 0xAA; // set first byte
uint8Array[1] = 0xBB; // set second byte
if(uint16array[0] === 0xBBAA) return "little endian";
if(uint16array[0] === 0xAABB) return "big endian";
else throw new Error("Something crazy just happened");
}
Dans votre cas, vous devrez probablement recréer le fichier en petit endian, ou parcourir toute la structure de données pour le rendre peu endian. En utilisant une torsion de la méthode ci-dessus, vous pouvez échanger l'endianité à la volée (ce n'est pas vraiment recommandé et n'a de sens que si la structure entière est du même type étroitement compressé, en réalité, vous pouvez créer une fonction de stub qui permute les octets selon les besoins):
function swapBytes(buf, size) {
var bytes = new Uint8Array(buf);
var len = bytes.length;
var holder;
if (size == 'Word') {
// 16 bit
for (var i = 0; i<len; i+=2) {
holder = bytes[i];
bytes[i] = bytes[i+1];
bytes[i+1] = holder;
}
} else if (size == 'DWORD') {
// 32 bit
for (var i = 0; i<len; i+=4) {
holder = bytes[i];
bytes[i] = bytes[i+3];
bytes[i+3] = holder;
holder = bytes[i+1];
bytes[i+1] = bytes[i+2];
bytes[i+2] = holder;
}
}
}
Tiré d'ici http://www.khronos.org/registry/typedarray/specs/latest/ (lorsque cette spécification est entièrement implémentée), vous pouvez utiliser:
new DataView(binaryArrayBuffer).getInt32(0, true) // For little endian
new DataView(binaryArrayBuffer).getInt32(0, false) // For big endian
Cependant, si vous ne pouvez pas utiliser ces méthodes parce qu'elles ne sont pas implémentées, vous pouvez toujours vérifier la valeur magique du fichier (presque tous les formats ont une valeur magique) sur l'en-tête pour voir si vous devez l'inverser selon vos endiannes.
De plus, vous pouvez enregistrer des fichiers spécifiques aux endiannes sur votre serveur et les utiliser en fonction des endiannes hôtes détectés.
Les autres réponses me semblent un peu dépassées, voici donc un lien vers les dernières spécifications:
http://www.khronos.org/registry/typedarray/specs/latest/#2.1
En particulier:
Les types de vue de tableau typé fonctionnent avec l'endianité de l'ordinateur hôte.
Le type DataView fonctionne sur des données avec une endianité spécifiée (big-endian ou little-endian).
Donc, si vous souhaitez lire/écrire des données en Big Endian (Network Byte Order), voir: http://www.khronos.org/registry/typedarray/specs/latest/#DATAVIEW
// For multi-byte values, the optional littleEndian argument
// indicates whether a big-endian or little-endian value should be
// read. If false or undefined, a big-endian value is read.
/** @returns {Boolean} true if system is big endian */
function isBigEndian() {
const array = new Uint8Array(4);
const view = new Uint32Array(array.buffer);
return !((view[0] = 1) & array[0]);
}
Comment ça fonctionne:
view[0] = 1
définit le tableau pour contenir la valeur 32 bits 1;!
opérateur au résultat de &
opération, tout en l'inversant pour qu'elle renvoie true pour big endian.